我创建了这样一个对象:

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 (or _pickle) vs pickle

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

import cPickle as pickle

在Python3中,cPickle重命名为_pickle,但不再需要这样做,因为pickle模块现在自动执行此操作-请参见What difference between pickle and _pickle in python 3?.

简而言之,当Python2和Python3中都有C版本时,您可以使用以下内容来确保代码使用C版本:

try:
    import cPickle as pickle
except ModuleNotFoundError:
    import pickle

数据流格式(协议)

pickle可以读写几种不同的、特定于Python的格式的文件,如documentation中所述,称为protocols,"协议版本0"是ASCII,因此是"人类可读的".版本>;0是二进制的,可用的最高值取决于使用的Python版本.默认值也取决于Python版本.在Python2中,默认为协议版本0,但在Python3.8.1中,默认为协议版本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对象,则只需指定一次协议:

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

Note:如果您所处的环境运行的是不同版本的Python,那么您可能希望显式地使用(即硬代码)所有人都可以读取的特定协议号(较新版本通常可以读取早期版本生成的文件).

多个对象

虽然泡菜文件can包含任意数量的泡菜对象,如上面的示例所示,但当它们的数量未知时,通常更容易将它们全部存储在某种大小可变的容器中,如listtupledict,并在单个调用中将它们全部写入文件:

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相关问答推荐

在Windows上启动新Python项目的正确步骤顺序

实现的差异取决于计算出的表达是直接返回还是首先存储在变量中然后返回

如何根据情况丢弃大Pandas 的前n行,使大Pandas 的其余部分完好无损

在应用循环中间保存pandas DataFrame

如何用symy更新分段函数

使用GEKKO在简单DTE系统中进行一致初始化

如何在msgraph.GraphServiceClient上进行身份验证?

如何检测背景有噪的图像中的正方形

如何将双框框列中的成对变成两个新列

如何删除索引过go 的lexsort深度可能会影响性能?' &>

用Python解密Java加密文件

无法使用requests或Selenium抓取一个href链接

如何在给定的条件下使numpy数组的计算速度最快?

Godot:需要碰撞的对象的AdditionerBody2D或Area2D以及queue_free?

形状弃用警告与组合多边形和多边形如何解决

如何在Python中使用Pandas将R s Tukey s HSD表转换为相关矩阵''

重置PD帧中的值

循环浏览每个客户记录,以获取他们来自的第一个/最后一个渠道

如何在FastAPI中替换Pydantic的constr,以便在BaseModel之外使用?'

Django抛出重复的键值违反唯一约束错误