3 pickle 模块的优缺点
优点
- 可以用来存储 Python 对象。我们不需要一次又一次地构造相同的对象。我们将创建一个对象,然后将其保存到磁盘中(pickling),以后再从磁盘中加载这个对象(unpickling),而不需要再次创建这个对象。
- 在机器学习中非常有用。一个机器学习模型是在一个非常大的数据集上训练的,而训练一个模型需要消耗大量的时间。因此,如果我们必须训练相同的模型,这将不是一个好的选择。为了避免或减少时间和艰苦的工作,pickling 是非常有用的。我们只需要训练一次我们的模型,然后将其保存在本地磁盘中,当我们需要测试我们的模型时,我们可以直接从磁盘中加载它,而不需要再次训练它。
- Python 的 pickle 模块比 json 模块可以序列化更多的类型。然而,并不是所有的东西都可以被 picklable。不可 pickable 对象的列表包括数据库连接、开放网络套接字、正在运行的线程。
缺点
- 缺乏安全性。避免从未知来源 unpickling 数据,因为它们可能包含恶意的或错误的数据。
根据官方文档:“pickle 模块并不安全,只能 unpickling 你信任的数据。黑客有可能构建恶意的 pickled 数据,然后在解压过程中执行任意代码。不要 unpickle 可能来自不信任的来源或可能被篡改的数据。如果你需要确保数据没有被篡改,请考虑用hmac 签名。如果你正在处理不受信任的数据,更安全的序列化格式,那么 json 可能更合适。”
- 兼容性太差。由于它只针对 Python,所以它不能保证跨语言的兼容性。甚至不同的 Python 版本之间也不兼容。这意味着在 Python 2.x 版本中完成的 pickling 可能在 Python 3.x 版本中无法工作。
4 扩展 pickle 模块的 dill 库
dill
模块扩展了 pickle 的功能。根据官方文档,它可以让你序列化一些不太常见的类型,如带 yield 的函数、嵌套函数、lambdas 和其他许多类型。
为了测试这个模块,你可以尝试 pickle 一个 lambda 函数。
import pickle square = lambda x: x * x my_pickle = pickle.dumps(square)
运行上述代码,会得到一个异常,因为 Python pickle 模块不能序列化一个 lambda 函数。
如果用 dill
库来序列化,如下:
import dill square = lambda x: x * x my_pickle = dill.dumps(square) print(my_pickle)
此时可以看到不会报错:
$ python dill_test.py b'\x80\x04\x95\xdb\x00\x00\x00\x00\x00\x00\x00\x8c\ndill._dill\x94\x8c\x10_create_function\x94\x93\x94(h\x00\x8c\x0c_create_code\x94\x93\x94(K\x01K\x00K\x00K\x01K\x02KCC\x08|\x00|\x00\x14\x00S\x00\x94N\x85\x94)\x8c\x01x\x94\x85\x94\x8c/E:\\Coding Workspaces\\PythonScripts\\dill_test.py\x94\x8c\x08<lambda>\x94K\x03C\x00\x94))t\x94R\x94c__builtin__\n__main__\nh\nNNt\x94R\x94}\x94}\x94\x8c\x0f__annotations__\x94}\x94s\x86\x94b.'
5 总结
在本文中,我们了解了 Python 中的 pickling(对象序列化) 和 unpickling (反序列化)操作,这些操作对于存储对象以供以后使用很有用。介绍了内置的 pickle 模块提供了诸如 load()
、loads()
、dump()
、dumps()
之类的方法,用于将 Python 对象与字节流之间的相互转换。
因为 Python 中一切皆对象的特点,所以 Python 中的元组、字典、列表,甚至 Python 类和函数也可以被序列化和反序列化。但它可能不支持跨语言、多 Python 版本的兼容性差。
另外,为了安全性,也应避免从未知来源解压,因为它们可能包含恶意的、错误的数据。