我创建了一个像这样的对象:
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 outp: company1 = Company('banana', 40) pickle.dump(company1, outp, pickle.HIGHEST_PROTOCOL) company2 = Company('spam', 42) pickle.dump(company2, outp, pickle.HIGHEST_PROTOCOL) del company1 del company2 with open('company_data.pkl', 'rb') as inp: company1 = pickle.load(inp) print(company1.name) # -> banana print(company1.value) # -> 40 company2 = pickle.load(inp) print(company2.name) # -> spam print(company2.value) # -> 42
您还可以定义自己的简单实用程序,如下所示,它打开文件并向其中写入单个对象:
def save_object(obj, filename): with open(filename, 'wb') as outp: # Overwrites any existing file. pickle.dump(obj, outp, pickle.HIGHEST_PROTOCOL) # sample usage save_object(company1, 'company1.pkl')
由于这是一个如此受欢迎的答案,我想谈谈一些稍微高级的使用主题。
cPickle
_pickle
实际使用模块几乎总是更可取,cPickle而不是pickle因为前者是用 C 编写的并且速度更快。它们之间有一些细微的差别,但在大多数情况下它们是等价的,C 版本将提供非常出色的性能。切换到它再简单不过了,只需将import语句更改为:
import
import cPickle as pickle
在 Python 3 中,cPickle已重命名_pickle,但不再需要这样做,因为pickle模块现在会自动执行- 看看 python3 中的 pickle 和 _pickle有什么区别?.
简而言之,您可以使用以下内容来确保您的代码在 Python 2 和 3 中都可用时 始终 使用 C 版本:
try: import cPickle as pickle except ModuleNotFoundError: import pickle
pickle可以读取和写入几种不同的、特定于 Python 的格式的文件,称为文档中描述的 协议 ,“协议版本 0”是 ASCII,因此是“人类可读的”。版本 > 0 是二进制的,可用的最高版本取决于使用的 Python 版本。默认值还取决于 Python 版本。在 Python 2 中,默认值为 Protocol version ,但在 Python 3.8.1 中,它是 Protocol version 。在 Python 3.x 中,该模块添加了一个,但在 Python 2 中不存在。0``4``pickle.DEFAULT_PROTOCOL
0``4``pickle.DEFAULT_PROTOCOL
幸运的是,每次调用都有简写pickle.HIGHEST_PROTOCOL(假设这是您想要的,并且您通常会这样做),只需使用文字数字-1——类似于通过负索引引用序列的最后一个元素。所以,而不是写:
pickle.HIGHEST_PROTOCOL
-1
pickle.dump(obj, outp, pickle.HIGHEST_PROTOCOL)
你可以写:
pickle.dump(obj, outp, -1)
Pickler无论哪种方式,如果您创建了一个用于多个泡菜操作的对象,您只需指定一次协议:
Pickler
pickler = pickle.Pickler(outp, -1) pickler.dump(obj1) pickler.dump(obj2) etc...
注意 :如果您在运行不同版本 Python 的环境中,那么您可能希望显式使用(即硬编码)所有它们都可以读取的特定协议号(更高版本通常可以读取由早期版本生成的文件) .
虽然泡菜文件 可以 包含任意数量的泡菜对象,如上面的示例所示,但当它们的数量未知时,通常更容易将它们全部存储在某种可变大小的容器中,例如 a list, tuple, ordict并写入在一次调用中将它们全部保存到文件中:
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 inp: tech_companies = pickle.load(inp)
主要优点是您不需要知道保存了多少对象实例以便稍后加载它们(尽管在没有这些信息的情况下这样做 是 可能的,但它需要一些稍微专门的代码)。就我个人而言,这就是下面示例代码中使用的方法:
class Company: def __init__(self, name, value): self.name = name self.value = value def pickle_loader(filename): """ Deserialize a file of pickled objects. """ with open(filename, "rb") as f: while True: try: yield pickle.load(f) except EOFError: break print('Companies in pickle file:') for company in pickle_loader('company_data.pkl'): print(' name: {}, value: {}'.format(company.name, company.value))