我创建了一个这样的对象:
company1.name = 'banana' company1.value = 40
我想保存该对象。我怎样才能做到这一点?
你可以使用pickle标准库中的模块。这是你的示例的基本应用:
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
ASCII
> 1
Python
Python 2
Protocol
04pickle.DEFAULT_PROTOCOL
幸运的是,pickle.HIGHEST_PROTOCOL在每个调用中都有一种写法(假设这就是你想要的,并且你通常会这样做),只需使用文字数字-1-类似于通过负索引引用序列的最后一个元素。因此,与其编写:
pickle.HIGHEST_PROTOCOL
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,tuple或dict写字一次调用即可将它们全部存储到文件中:
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)
主要优点是你无需知道保存了多少个对象实例即可在以后加载它们(尽管如果没有该信息就可以这样做,但它需要一些专门的代码)。请参阅相关问题的答案在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))