python pickle module

源代码: Lib/pickle.py

pickle 模块实现了对一个 Python 对象结构的二进制序列化(pickling)和反序列化(unpickling)。

pickling 是将 Python 对象及其所拥有的层次结构转化为一个字节流的过程, unpickling 是相反的操作,会将字节流转化回一个对象层次结构。

注: pickle 模块并不安全。你只应该对你信任的数据进行unpickle操作。

与 json 模块的比较

Pickle 协议和 JSON (JavaScript Object Notation) 间有着本质的不同:

  • JSON 是一个文本序列化格式(它输出 unicode 文本,尽管在大多数时候它会接着以 utf-8 编码),而 pickle 是一个二进制序列化格式;
  • JSON 是我们可以直观阅读的,而 pickle 不是;
  • JSON是可互操作的,在Python系统之外广泛使用,而pickle则是Python专用的;
  • 默认情况下,JSON 只能表示 Python 内置类型的子集,不能表示自定义的类;但 pickle 可以表示大量的 Python 数据类型(可以合理使用 Python 的对象内省功能自动地表示大多数类型,复杂情况可以通过实现 specific object APIs 来解决)。
  • 不像pickle,对一个不信任的JSON进行反序列化的操作本身不会造成任意代码执行漏洞。

模块接口

要序列化某个包含层次结构的对象,只需调用 dumps() 函数即可。同样,要反序列化数据流,可以调用 loads() 函数。但是,如果要对序列化和反序列化加以更多的控制,可以分别创建 PicklerUnpickler 对象。

pickle模块包含了以下常量:

pickle.HIGHEST_PROTOCOL

整数,可用的最高 协议版本。此值可以作为 协议 值传递给 dump() 和 dumps() 函数,以及 Pickler 的构造函数。

pickle.DEFAULT_PROTOCOL

整数,用于 pickle 数据的默认 协议版本。它可能小于 HIGHEST_PROTOCOL。它在 Python 3.4 中首次引入,与之前的版本不兼容。

在 3.0 版更改: 默认协议版本是 3。

在 3.8 版更改: 默认协议版本是 4。

pickle 模块提供了以下方法:

pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)

将对象 obj 封存以后的对象写入已打开的 file object file。它等同于 Pickler(file, protocol).dump(obj)。

参数 file、protocol、fix_imports 和 buffer_callback 的含义与它们在 Pickler 的构造函数中的含义相同。

在 3.8 版更改: 加入了 buffer_callback 参数。

pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)

将 obj 封存以后的对象作为 bytes 类型直接返回,而不是将其写入到文件。

参数 protocol、fix_imports 和 buffer_callback 的含义与它们在 Pickler 的构造函数中的含义相同。

在 3.8 版更改: 加入了 buffer_callback 参数。

pickle.load(file, *, fix_imports=True, encoding=”ASCII”, errors=”strict”, buffers=None)

从已打开的 file object 文件 中读取封存后的对象,重建其中特定对象的层次结构并返回。它相当于 Unpickler(file).load()。

Pickle 协议版本是自动检测出来的,所以不需要参数来指定协议。封存对象以外的其他字节将被忽略。

参数 file、fix_imports、encoding、errors、strict 和 buffers 的含义与它们在 Unpickler 的构造函数中的含义相同。

在 3.8 版更改: 加入了 buffers 参数。

pickle.loads(bytes_object, *, fix_imports=True, encoding=”ASCII”, errors=”strict”, buffers=None)

对于封存生成的对象 bytes_object,还原出原对象的结构并返回。

Pickle 协议版本是自动检测出来的,所以不需要参数来指定协议。封存对象以外的其他字节将被忽略。

参数 file、fix_imports、encoding、errors、strict 和 buffers 的含义与它们在 Unpickler 的构造函数中的含义相同。

在 3.8 版更改: 加入了 buffers 参数。

pickle 模块定义了以下 3 个异常:

exception pickle.PickleError

其他 pickle 异常的基类。它是 Exception 的一个子类。

exception pickle.PicklingError

Pickler 遇到无法解封的对象时抛出此错误。它是 PickleError 的子类。

参考 可以被封存/解封的对象 来了解哪些对象可以被封存。

exception pickle.UnpicklingError

当解封出错时抛出此异常,例如数据损坏或对象不安全。它是 PickleError 的子类。

注意,解封时可能还会抛出其他异常,包括(但不限于) AttributeError、EOFError、ImportError 和 IndexError。

pickle 模块包含了 3 个类,Pickler、Unpickler 和 PickleBuffer:

class pickle.Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None)

它接受一个二进制文件用于写入 pickle 数据流。

protocol :可选参数,是一个整数,告知 pickler 使用指定的协议,可选择的协议范围从 0 到 HIGHEST_PROTOCOL。如果没有指定,这一参数默认值为 DEFAULT_PROTOCOL。指定一个负数就相当于指定 HIGHEST_PROTOCOL。

file:参数必须有一个 write() 方法,该 write() 方法要能接收字节作为其唯一参数。因此,它可以是一个打开的磁盘文件(用于写入二进制内容),也可以是一个 io.BytesIO 实例,也可以是满足这一接口的其他任何自定义对象。

fix_imports:参数如果为 True 且 protocol 小于 3,pickle 将尝试将 Python 3 中的新名称映射到 Python 2 中的旧模块名称,因此 Python 2 也可以读取封存的数据流。

buffer_callback :参数如果为 None(默认情况),缓冲区视图(buffer view)将会作为 pickle 流的一部分被序列化到 file 中。如果 buffer_callback 不为 None,那它可以用缓冲区视图调用任意次。如果某次调用返回了 False 值(例如 None),则给定的缓冲区是 带外的,否则缓冲区是带内的(例如保存在了 pickle 流里面)。如果 buffer_callback 不是 None 且 protocol 是 None 或小于 5,就会出错。

在 3.8 版更改: 加入了 buffer_callback 参数。

dump(obj)

将 obj 封存后的内容写入已打开的文件对象,该文件对象已经在构造函数中指定。

persistent_id(obj)

默认无动作,子类继承重载时使用。

如果 persistent_id() 返回 None,obj 会被照常 pickle。如果返回其他值,Pickler 会将这个函数的返回值作为 obj 的持久化 ID(Pickler 本应得到序列化数据流并将其写入文件,若此函数有返回值,则得到此函数的返回值并写入文件)。这个持久化 ID 的解释应当定义在 Unpickler.persistent_load() 中(该方法定义还原对象的过程,并返回得到的对象)。

注意,persistent_id() 的返回值本身不能拥有持久化 ID。

dispatch_table

Pickler 对象的 dispatch 表是 copyreg.pickle() 中用到的 reduction 函数 的注册。dispatch 表本身是一个 class 到其 reduction 函数的映射键值对。一个 reduction 函数只接受一个参数,就是其关联的 class,函数行为应当遵守 reduce() 接口规范。

Pickler 对象默认并没有 dispatch_table 属性,该对象默认使用 copyreg 模块中定义的全局 dispatch 表。如果要为特定 Pickler 对象自定义序列化过程,可以将 dispatch_table 属性设置为类字典对象(dict-like object)。另外,如果 Pickler 的子类设置了 dispatch_table 属性,则该子类的实例会使用这个表作为默认的 dispatch 表。

reducer_override(self, obj)

可以在 Pickler 的子类中定义的特殊 reducer。此方法的优先级高于 dispatch_table 中的任何 reducer。它应该与 reduce() 方法遵循相同的接口,它也可以返回 NotImplemented,这将使用 dispatch_table 里注册的 reducer 来封存 obj。

fast

已弃用。设为 True 则启用快速模式。快速模式禁用了“备忘录” (memo) 的使用,即不生成多余的 PUT 操作码来加快封存过程。不应将其与自指 (self-referential) 对象一起使用,否则将导致 Pickler 无限递归。

class pickle.Unpickler(file, *, fix_imports=True, encoding=”ASCII”, errors=”strict”, buffers=None)

它接受一个二进制文件用于读取 pickle 数据流。

Pickle 协议版本是自动检测出来的,所以不需要参数来指定协议。

file :参数必须有三个方法,read() 方法接受一个整数参数,readinto() 方法接受一个缓冲区作为参数,readline() 方法不需要参数,这与 io.BufferedIOBase 里定义的接口是相同的。因此 file 可以是一个磁盘上用于二进制读取的文件,也可以是一个 io.BytesIO 实例,也可以是满足这一接口的其他任何自定义对象。

fix_imports, encoding 和 errors:可选的参数是 ,用于控制由Python 2 生成的 pickle 流的兼容性。如果 fix_imports 为 True,则 pickle 将尝试将旧的 Python 2 名称映射到 Python 3 中对应的新名称。encoding 和 errors 参数告诉 pickle 如何解码 Python 2 存储的 8 位字符串实例;这两个参数默认分别为 ‘ASCII’ 和 ‘strict’。encoding 参数可置为 ‘bytes’ 来将这些 8 位字符串实例读取为字节对象。读取 NumPy array 和 Python 2 存储的 datetime、date 和 time 实例时,请使用 encoding=’latin1’。

buffers :如果为 None(默认值),则反序列化所需的所有数据都必须包含在 pickle 流中。这意味着在实例化 Pickler 时(或调用 dump() 或 dumps() 时),参数 buffer_callback 为 None。如果 buffers 不为 None,则每次 pickle 流引用 带外 缓冲区视图时,消耗的对象都应该是可迭代的启用缓冲区的对象。这样的缓冲区应该按顺序地提供给 Pickler 对象的 buffer_callback 方法。

在 3.8 版更改: 加入了 buffers 参数。

load()

从构造函数中指定的文件对象里读取封存好的对象,重建其中特定对象的层次结构并返回。封存对象以外的其他字节将被忽略。

persistent_load(pid)

默认抛出 UnpicklingError 异常。

如果定义了此方法,persistent_load() 应当返回持久化 ID pid 所指定的对象。 如果遇到无效的持久化 ID,则应当引发 UnpicklingError。

find_class(module, name)

如有必要,导入 module 模块并返回其中名叫 name 的对象,其中 module 和 name 参数都是 str 对象。注意,不要被这个函数的名字迷惑, find_class() 同样可以用来导入函数。

子类可以重载此方法,来控制加载对象的类型和加载对象的方式,从而尽可能降低安全风险。

class pickle.PickleBuffer(buffer)

缓冲区的包装器 (wrapper),缓冲区中包含着可封存的数据。

buffer 必须是一个 buffer-providing 对象,比如 bytes-like object 或多维数组。

PickleBuffer 本身就可以生成缓冲区对象,因此可以将其传递给需要缓冲区生成器的其他 API,比如 memoryview。

PickleBuffer 对象只能用 pickle 版本 5 及以上协议进行序列化。它们符合 带外序列化 的条件。

3.8 新版功能.

raw()

返回该缓冲区底层内存区域的 memoryview。 返回的对象是一维的、C 连续布局的 memoryview,格式为 B (无符号字节)。 如果缓冲区既不是 C 连续布局也不是 Fortran 连续布局的,则抛出 BufferError 异常。

release()

释放由 PickleBuffer 占用的底层缓冲区。

示例

请使用 dump() 函数

1
2
3
4
5
6
7
8
9
10
11
12
import pickle

# An arbitrary collection of objects supported by pickle.
data = {
'a': [1, 2.0, 3, 4+6j],
'b': ("character string", b"byte string"),
'c': {None, True, False}
}

with open('data.pickle', 'wb') as f:
# Pickle the 'data' dictionary using the highest protocol available.
pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

请使用 load() 函数

1
2
3
4
5
6
import pickle

with open('data.pickle', 'rb') as f:
# The protocol version used is detected automatically, so we do not
# have to specify it.
data = pickle.load(f)

参考

https://docs.python.org/zh-cn/3/library/pickle.html#module-pickle

-------------本文结束感谢您的阅读-------------