ZetCode

Python Pickle

最后修改于 2024 年 1 月 29 日

Python Pickle 教程展示了如何使用 Pickle 模块在 Python 中进行数据序列化。

Pickle 模块

Pickle 模块实现了用于序列化和反序列化 Python 对象结构的二进制协议。 序列化是将内存中的对象转换为字节流的过程,字节流可以存储在磁盘上或通过网络发送。 反序列化是将字节流转换为 Python 对象的过程。

此过程也称为 pickling/unpickling 或 marshalling/unmarshalling。

pickletools 模块包含用于分析 Pickle 生成的数据流的工具。

注意:使用 Pickle 模块进行数据序列化是不安全的。 该文档强调,我们永远不应该对来自不受信任的来源或通过不安全网络传输的数据进行 unpickle 操作。

Python Pickle 序列化

以下示例将数据序列化为二进制文件。

simple_write.py
#!/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 数据。

simple_read.py
#!/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 表示数据的重构对象层次结构。 数据必须是类似字节的对象。

dumps_loads.py
#!/usr/bin/python

import pickle


data = [1, 2, 3, 4, 5]

dumped = pickle.dumps(data)
print(dumped)

loaded = pickle.loads(dumped)
print(loaded)

在该示例中,我们使用 dumpsloads 序列化和反序列化 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__ 函数。

words.txt
blue, rock, water, sky, cloud, forest, hawk, falcon

这是 words.txt 文件

colours.txt
red, green, blue, pink, orange

这是 colours.txt 文件

state.py
#!/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。

insec.py
#!/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

来源

pickle — Python 对象序列化

在本文中,我们使用了 Python pickle 模块。

作者

我叫 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程