在Python中如何保持对象(对象持久化)


在Python中如何保持对象(对象持久化)


您可以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)vspickle

实际使用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版本0,但在Python 3.6中,它是Protocol版本3。在Python 3.x中,模块pickle.DEFAULT_PROTOCOL添加了一个,但在Python 2中不存在。

幸运的是pickle.HIGHEST_PROTOCOL,每次调用都有写入的简写(假设这是你想要的,而且你通常这样做) - 只需使用文字数字-1。所以,而不是写:

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

你可以写:

pickle.dump(obj, output, -1)

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

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

多个对象

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

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)

主要的优点是您不需要知道保存了多少对象实例以便稍后加载它们(尽管这样做没有这些信息是可能的,它需要一些稍微专门的代码),这是适应这里的例子:

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))