Python-保存对象(数据持久性)

发布于 2021-02-02 23:22:19

我创建了一个这样的对象:

company1.name = 'banana' 
company1.value = 40

我想保存该对象。我怎样才能做到这一点?

关注者
0
被浏览
153
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    你可以使用pickle标准库中的模块。这是你的示例的基本应用:

    import pickle
    
    class Company(object):
        def __init__(self, name, value):
            self.name = name
            self.value = value
    
    with open('company_data.pkl', 'wb') as output:
        company1 = Company('banana', 40)
        pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL)
    
        company2 = Company('spam', 42)
        pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL)
    
    del company1
    del company2
    
    with open('company_data.pkl', 'rb') as input:
        company1 = pickle.load(input)
        print(company1.name)  # -> banana
        print(company1.value)  # -> 40
    
        company2 = pickle.load(input)
        print(company2.name) # -> spam
        print(company2.value)  # -> 42
    

    你还可以定义自己的简单实用程序,如下所示,该实用程序打开文件并向其中写入单个对象:

    def save_object(obj, filename):
        with open(filename, 'wb') as output:  # Overwrites any existing file.
            pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
    
    # sample usage
    save_object(company1, 'company1.pkl')
    

    更新资料

    由于这是一个非常受欢迎的答案,因此,我想谈谈一些高级用法主题。

    cPickle(或_pickle)与pickle

    实际使用该cPickle模块几乎总是可取的,而不是pickle因为该模块是用C编写的并且速度更快。它们之间有一些细微的差异,但是在大多数情况下它们是等效的,并且C版本将提供非常优越的性能。切换到它再简单不过,只需将import语句更改为此:

    import cPickle as pickle
    

    在Python 3中,它cPickle已被重命名_pickle,但是不再需要执行此操作,因为该pickle模块现在可以自动执行此操作-请参阅python 3中的pickle和_pickle有什么区别?。

    总结是,你可以使用类似以下内容的代码来确保你的代码在Python 2和3中都可用时始终使用C版本:

    try:
        import cPickle as pickle
    except ModuleNotFoundError:
        import pickle
    

    数据流格式(协议)

    pickle可以使用多种不同的特定于Python的格式读写文件,这些格式称为文档中所述的协议,“协议版本0”为ASCII,因此“易于阅读”。版本> 1是二进制文件,可用的最高版本取决于所使用的Python版本。默认值还取决于Python版本。在Python 2中,默认值是Protocol版本,但在Python 3.8.1中,它是Protocol版本。在Python 3.x中,该模块已添加,但在Python 2中不存在。04pickle.DEFAULT_PROTOCOL

    幸运的是,pickle.HIGHEST_PROTOCOL在每个调用中都有一种写法(假设这就是你想要的,并且你通常会这样做),只需使用文字数字-1-类似于通过负索引引用序列的最后一个元素。因此,与其编写:

    pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
    

    你可以这样写:

    pickle.dump(obj, output, -1)
    

    无论哪种方式,如果你创建了一个Pickler用于多个酸洗操作的对象,则只需指定一次协议:

    pickler = pickle.Pickler(output, -1)
    pickler.dump(obj1)
    pickler.dump(obj2)
       etc...
    

    注意:如果你正在运行不同版本的Python的环境中,则可能需要显式使用(即,硬编码)所有这些协议都可以读取的特定协议编号(较新的版本通常可以读取较早版本产生的文件) 。

    多个物件

    虽然泡菜文件可以包含如上述样品中,当有这些数目不详的任何数量的腌制对象的,它往往更容易将其全部保存在某种可变大小的容器,就像一个list,tupledict写字一次调用即可将它们全部存储到文件中:

    tech_companies = [
        Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
    ]
    save_object(tech_companies, 'tech_companies.pkl')
    

    然后使用以下命令还原列表及其中的所有内容:

    with open('tech_companies.pkl', 'rb') as input:
        tech_companies = pickle.load(input)
    

    主要优点是你无需知道保存了多少个对象实例即可在以后加载它们(尽管如果没有该信息就可以这样做,但它需要一些专门的代码)。请参阅相关问题的答案在pickle文件中保存和加载多个对象?有关执行此操作的不同方法的详细信息。我个人最喜欢@Lutz Prechelt的答案。它适用于此处的示例:

    class Company:
        def __init__(self, name, value):
            self.name = name
            self.value = value
    
    def pickled_items(filename):
        """ Unpickle a file of pickled data. """
        with open(filename, "rb") as f:
            while True:
                try:
                    yield pickle.load(f)
                except EOFError:
                    break
    
    print('Companies in pickle file:')
    for company in pickled_items('company_data.pkl'):
        print('  name: {}, value: {}'.format(company.name, company.value))
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看