我创建了一个像这样的对象:
company1.name = 'banana'
company1.value = 40
我想保存这个对象。我怎样才能做到这一点?
最佳答案
您可以使用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
)与pickle
实际使用 cPickle
几乎总是更好的选择module 而不是 pickle
因为前者是用 C 编写的并且速度更快。它们之间存在一些细微的差异,但在大多数情况下它们是等效的,并且 C 版本将提供非常优越的性能。切换到它再简单不过了,只需将 import
语句更改为:
import cPickle as pickle
在 Python 3 中,cPickle
被重命名为 _pickle
,但不再需要这样做,因为 pickle
模块现在会自动执行此操作 - 请参阅What difference between pickle and _pickle in python 3? .
概要是,您可以使用如下内容来确保您的代码在 Python 2 和 3 中都可用时始终使用 C 版本:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
数据流格式(协议(protocol))
pickle
可以读取和写入几种不同的、特定于 Python 的格式的文件,称为协议(protocol),如 documentation 中所述。 ,“协议(protocol)版本 0”是 ASCII,因此是“人类可读的”。 > 0 的版本是二进制的,可用的最高版本取决于所使用的 Python 版本。默认值还取决于 Python 版本。在 Python 2 中,默认协议(protocol)版本为 0
,但在 Python 3.8.1 中,默认协议(protocol)版本为 4
。在 Python 3.x 中,该模块添加了 pickle.DEFAULT_PROTOCOL
,但在 Python 2 中不存在。
幸运的是,在每次调用中都有编写 pickle.HIGHEST_PROTOCOL
的简写(假设这就是您想要的,并且您通常这样做),只需使用文字数字 -1
— 类似通过负索引引用序列的最后一个元素。
因此,不要写:
pickle.dump(obj, outp, pickle.HIGHEST_PROTOCOL)
你可以这样写:
pickle.dump(obj, outp, -1)
无论哪种方式,如果您创建了一个用于多个 pickle 操作的 Pickler
对象,则只需指定一次协议(protocol):
pickler = pickle.Pickler(outp, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
注意:如果您处于运行不同版本的 Python 的环境中,那么您可能希望显式使用(即硬编码)所有人都可以读取的特定协议(protocol)号(稍后会介绍)版本通常可以读取早期版本生成的文件)。
多个对象
虽然 pickle 文件可以包含任意数量的 pickle 对象,如上面的示例所示,但当它们的数量未知时,通常更容易将它们全部存储在某种变量中 -大小的容器,例如 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)
主要优点是您不需要知道保存了多少对象实例以便稍后加载它们(尽管在没有这些信息的情况下这样做是可能的,但它需要一些稍微专门化的代码)。查看相关问题的答案Saving and loading multiple objects in pickle file?有关执行此操作的不同方法的详细信息。我个人喜欢@Lutz Prechelt 的answer最好的,所以这就是下面示例代码中使用的方法:
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))
关于python - 保存对象(数据持久化),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58565910/