Python Pickle
最后修改于 2024 年 1 月 29 日
Python Pickle 教程展示了如何使用 Pickle 模块在 Python 中进行数据序列化。
Pickle 模块
Pickle 模块实现了用于序列化和反序列化 Python 对象结构的二进制协议。 序列化是将内存中的对象转换为字节流的过程,字节流可以存储在磁盘上或通过网络发送。 反序列化是将字节流转换为 Python 对象的过程。
此过程也称为 pickling/unpickling 或 marshalling/unmarshalling。
pickletools
模块包含用于分析 Pickle 生成的数据流的工具。
Python Pickle 序列化
以下示例将数据序列化为二进制文件。
#!/usr/bin/python import pickle data = { 'a': [1, 4.0, 3, 4+6j], 'b': ("a red fox", b"and old falcon"), 'c': {None, True, False} } with open('data.bin', 'wb') as f: pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
我们有一个包含不同数据类型的字典。 这些数据被 pickle 到一个二进制文件中。
with open('data.bin', 'wb') as f: pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
dump
函数将对象的 pickle 表示形式写入文件对象。 随着时间的推移,已经开发了几种协议。 协议版本决定了序列化过程的能力。 在我们的代码中,我们选择最高的协议版本。
$ hexdump -C data.bin 00000000 80 05 95 75 00 00 00 00 00 00 00 7d 94 28 8c 01 |...u.......}.(..| 00000010 61 94 5d 94 28 4b 01 47 40 10 00 00 00 00 00 00 |a.].(K.G@.......| 00000020 4b 03 8c 08 62 75 69 6c 74 69 6e 73 94 8c 07 63 |K...builtins...c| 00000030 6f 6d 70 6c 65 78 94 93 94 47 40 10 00 00 00 00 |omplex...G@.....| 00000040 00 00 47 40 18 00 00 00 00 00 00 86 94 52 94 65 |..G@.........R.e| 00000050 8c 01 62 94 8c 09 61 20 72 65 64 20 66 6f 78 94 |..b...a red fox.| 00000060 43 0e 61 6e 64 20 6f 6c 64 20 66 61 6c 63 6f 6e |C.and old falcon| 00000070 94 86 94 8c 01 63 94 8f 94 28 89 88 4e 90 75 2e |.....c...(..N.u.| 00000080
二进制文件无法使用简单的文本编辑器读取;我们需要可以使用十六进制数据的工具。
Python Pickle 反序列化
在下一个示例中,我们从二进制文件 unpickle 数据。
#!/usr/bin/python import pickle with open('data.bin', 'rb') as f: data = pickle.load(f) print(data)
load
函数从文件对象读取对象的 pickle 表示形式,并返回重构的对象。
$ ./simple_read.py {'a': [1, 4.0, 3, (4+6j)], 'b': ('a red fox', b'and old falcon'), 'c': {False, True, None}}
我们已成功重新创建了字典对象。
Python Pickle dumps/loads
dumps
函数以字节对象的形式返回对象的 pickle 表示形式,而不是将其写入文件。 loads
函数返回对象的 pickle 表示数据的重构对象层次结构。 数据必须是类似字节的对象。
#!/usr/bin/python import pickle data = [1, 2, 3, 4, 5] dumped = pickle.dumps(data) print(dumped) loaded = pickle.loads(dumped) print(loaded)
在该示例中,我们使用 dumps
和 loads
序列化和反序列化 Python 列表。
$ ./dumps_loads.py b'\x80\x04\x95\x0f\x00\x00\x00\x00\x00\x00\x00]\x94(K\x01K\x02K\x03K\x04K\x05e.' [1, 2, 3, 4, 5]
Python Pickle __getstate__/__setstate__
可以使用 __getstate__
和 __setstate__
函数影响 pickling 和 unpickling 的过程。 在 pickling 时调用 __getstate__
函数,在 unpickling 时调用 __setstate__
函数。
blue, rock, water, sky, cloud, forest, hawk, falcon
这是 words.txt
文件
red, green, blue, pink, orange
这是 colours.txt
文件
#!/usr/bin/python import pickle class MyData: def __init__(self, filename): self.name = filename self.fh = open(filename) def __getstate__(self): odict = self.__dict__.copy() print(odict) del odict['fh'] return odict def __setstate__(self, dict): fh = open(dict['name']) self.name = dict['name'] self.fh = fh obj = MyData('words.txt') res = pickle.loads(pickle.dumps(obj)) print(res.fh.read()) obj2 = MyData('colours.txt') res = pickle.loads(pickle.dumps(obj2)) print(res.fh.read())
在该示例中,我们在 __setstate__
和 __getstate__
成员函数中存储和删除文件句柄。
$ ./state.py {'name': 'words.txt', 'fh': <_io.TextIOWrapper name='words.txt' mode='r' encoding='UTF-8'>} blue, rock, water, sky, cloud, forest, hawk, falcon {'name': 'colours.txt', 'fh': <_io.TextIOWrapper name='colours.txt' mode='r' encoding='UTF-8'>} red, green, blue, pink, orange
Python Pickle 是不安全的
pickle
模块是不安全的。 该模块是一个虚拟机,它使用预定义的 opcode 来完成其工作。 通过使用专门制作的二进制字符串,攻击者可以启动系统命令,这些命令可能会损坏数据或启动反向 shell。
#!/usr/bin/python import pickle pickle.loads(b"cos\nsystem\n(S'ls -l'\ntR.")
此示例启动 Linux ls
命令。
$ ./insec.py total 36 drwxr-xr-x 2 user2 user2 4096 Aug 13 16:16 Desktop drwxr-xr-x 2 user2 user2 4096 Aug 13 16:18 Documents drwxr-xr-x 2 user2 user2 4096 Aug 13 16:16 Downloads -rwxr-xr-x 1 user2 user2 79 Aug 29 11:08 insec.py drwxr-xr-x 2 user2 user2 4096 Aug 13 16:16 Music drwxr-xr-x 2 user2 user2 4096 Aug 13 16:16 Pictures drwxr-xr-x 2 user2 user2 4096 Aug 13 16:16 Public drwxr-xr-x 2 user2 user2 4096 Aug 13 16:16 Templates drwxr-xr-x 2 user2 user2 4096 Aug 13 16:16 Videos
来源
在本文中,我们使用了 Python pickle 模块。
作者
列出所有 Python 教程。