1. 知识导图
2. 序列化与反序列化
2.1 定义与原理
序列化(Pickling)是将Python对象及其所拥有的层次结构转化为一个字节流的过程,而反序列化(Unpickling)是将字节流转化回一个对象层次结构的过程。
原理:pickle模块通过跟踪已被序列化的对象,避免了重复序列化,支持递归对象和共享对象。它还可以透明地存储并保存类实例。
2.2 示例
import pickle
# 序列化
data = {'a': [1, 2.0, 3+4j], 'b': ("character string", b"byte string"), 'c': {None, True, False}}
with open('data.pickle', 'wb') as f:
pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
# 反序列化
with open('data.pickle', 'rb') as f:
loaded_data = pickle.load(f)
print(loaded_data)
3. 与其他模块的关系
3.1 与marshal模块的关系
pickle模块与marshal模块的主要区别在于pickle支持递归对象和共享对象,而marshal不支持。
表3.1 pickle与marshal模块对比
特性picklemarshal递归对象支持是否共享对象支持是否用户定义类支持是否跨版本兼容性是否
3.2 与json模块的比较
pickle是Python专用的二进制序列化格式,而json是文本序列化格式,广泛用于Python系统之外。
表3.2 pickle与json模块对比
特性picklejson序列化格式二进制文本可读性否是跨语言支持否是自定义类支持是否
4. 数据流格式
pickle模块使用Python专属的数据格式,支持多种协议版本,从v0到v5。
表4.1 pickle协议版本
协议版本特性兼容性v0人类可读所有Python版本v1二进制格式所有Python版本v2新式类支持Python 2.3+v3支持bytes对象Python 3.0-3.7v4大对象支持Python 3.4+v5带外数据支持Python 3.8+
5. 模块接口
5.1 主要函数
- o pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)
- o pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)
- o pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)
- o pickle.loads(data, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)
5.2 异常
- o pickle.PickleError
- o pickle.PicklingError
- o pickle.UnpicklingError
6. 可以被封存/解封的对象
可以被封存的对象包括:
- o 内置常量 (None, True, False, Ellipsis, NotImplemented)
- o 整数、浮点数、复数
- o 字符串、字节串、字节数组
- o 只包含可封存对象的元组、列表、集合和字典
- o 可在模块最高层级上访问的函数和类
- o 类的实例(仅限可封存的状态)
7. 封存类实例
7.1 特殊方法
- o __getnewargs_ex__()
- o __getnewargs__()
- o __getstate__()
- o __setstate__()
- o __reduce__()
- o __reduce_ex__()
7.2 示例
class TextReader:
def __init__(self, filename):
self.filename = filename
self.file = open(filename)
self.lineno = 0
def readline(self):
self.lineno += 1
line = self.file.readline()
if not line:
return None
if line.endswith('\n'):
line = line[:-1]
return "%i: %s" % (self.lineno, line)
def __getstate__(self):
state = self.__dict__.copy()
del state['file']
return state
def __setstate__(self, state):
self.__dict__.update(state)
self.file = open(self.filename)
for _ in range(self.lineno):
self.file.readline()
self.file = open(self.filename)
8. 持久化外部对象
8.1 示例
import pickle
import sqlite3
from collections import namedtuple
MemoRecord = namedtuple("MemoRecord", "key, task")
class DBPickler(pickle.Pickler):
def persistent_id(self, obj):
if isinstance(obj, MemoRecord):
return ("MemoRecord", obj.key)
return None
class DBUnpickler(pickle.Unpickler):
def __init__(self, file, connection):
super().__init__(file)
self.connection = connection
def persistent_load(self, pid):
cursor = self.connection.cursor()
type_tag, key_id = pid
if type_tag == "MemoRecord":
cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),))
key, task = cursor.fetchone()
return MemoRecord(key, task)
raise pickle.UnpicklingError("unsupported persistent object")
9. Dispatch表
9.1 示例
import io
import pickle
import copyreg
f = io.BytesIO()
p = pickle.Pickler(f)
p.dispatch_table = copyreg.dispatch_table.copy()
p.dispatch_table[SomeClass] = reduce_SomeClass
10. 处理有状态的对象
10.1 示例
class TextReader:
def __init__(self, filename):
self.filename = filename
self.file = open(filename)
self.lineno = 0
def readline(self):
self.lineno += 1
line = self.file.readline()
if not line:
return None
if line.endswith('\n'):
line = line[:-1]
return "%i: %s" % (self.lineno, line)
def __getstate__(self):
state = self.__dict__.copy()
del state['file']
return state
def __setstate__(self, state):
self.__dict__.update(state)
self.file = open(self.filename)
for _ in range(self.lineno):
self.file.readline()
self.file = open(self.filename)
11. 类型,函数和其他对象的自定义归约
11.1 示例
import io
import pickle
class MyClass:
my_attribute = 1
class MyPickler(pickle.Pickler):
def reducer_override(self, obj):
if getattr(obj, "__name__", None) == "MyClass":
return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute})
return NotImplemented
f = io.BytesIO()
p = MyPickler(f)
p.dump(MyClass)
12. 外部缓冲区
12.1 示例
class ZeroCopyByteArray(bytearray):
def __reduce_ex__(self, protocol):
if protocol >= 5:
return type(self)._reconstruct, (PickleBuffer(self),), None
return type(self)._reconstruct, (bytearray(self),)
@classmethod
def _reconstruct(cls, obj):
with memoryview(obj) as m:
obj = m.obj
if type(obj) is cls:
return obj
return cls(obj)
13. 限制全局变量
13.1 示例
import builtins
import io
import pickle
safe_builtins = {'range', 'complex', 'set', 'frozenset', 'slice'}
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))
def restricted_loads(s):
return RestrictedUnpickler(io.BytesIO(s)).load()
14. 性能
较新版本的pickle协议(第2版或更高)具有针对某些常见特性和内置类型的高效二进制编码格式。此外,pickle模块还拥有一个以C编写的透明优化器。
15. 学习总结
15.1 学习路线
- 1. 理解序列化与反序列化的基本概念
- 2. 掌握pickle模块的基本用法
- 3. 了解pickle与其他模块的区别
- 4. 学习pickle的数据流格式和协议版本
- 5. 掌握pickle模块的接口和异常处理
- 6. 学习如何封存和解封类实例
- 7. 了解持久化外部对象的方法
- 8. 学习Dispatch表的使用
- 9. 掌握处理有状态对象的方法
- 10. 学习自定义归约的方法
- 11. 了解外部缓冲区的使用
- 12. 学习限制全局变量的方法
- 13. 了解pickle的性能优化
15.2 学习总结
通过本教程,我们可以掌握Python内置模块pickle的基本用法和高级特性。pickle模块是Python中非常强大的工具,可以用于对象的序列化和反序列化,适用于多种应用场景。
持续更新Python编程学习日志与技巧,敬请关注!