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 教程。