知识拓展:Python序列化模块pickle 模块详解
Python pickle 模块学习笔记
1. 简介
pickle 是 Python 的标准序列化模块,用于将 Python 对象转换为字节流(序列化)以及将字节流恢复为对象(反序列化)。它支持几乎所有的 Python 数据类型和对象。
官方文档:https://docs.python.org/zh-cn/3/library/pickle.html
序列化模块:marshal详解
2. 核心方法
pickle 模块提供了四个主要方法:
-
pickle.dump(obj, file)
- 将对象序列化并写入文件
- 需要以二进制写入模式打开文件(‘wb’)
# 示例:序列化基本数据类型到文件 basic_data = { 'int': 42, 'float': 3.14, 'str': 'Hello Pickle', 'list': [1, 2, 3], 'dict': {'a': 1, 'b': 2}, 'tuple': (4, 5, 6), 'bool': True, 'none': None } with open('basic_data.pkl', 'wb') as f: pickle.dump(basic_data, f)
-
pickle.load(file)
- 从文件中读取并反序列化为对象
- 需要以二进制读取模式打开文件(‘rb’)
# 示例:从文件中读取序列化的数据 with open('basic_data.pkl', 'rb') as f: loaded_data = pickle.load(f) print("读取的数据:", loaded_data)
-
pickle.dumps(obj)
- 将对象序列化为字节串
- 返回 bytes 类型数据
# 示例:将数据序列化为字节串 bytes_data = pickle.dumps(basic_data) print("序列化后的字节串类型:", type(bytes_data)) print("字节串长度:", len(bytes_data))
-
pickle.loads(bytes)
- 将字节串反序列化为对象
- 接收 bytes 类型数据
# 示例:从字节串恢复数据 recovered_data = pickle.loads(bytes_data) print("恢复的数据:", recovered_data)
3. 支持的数据类型
3.1 基本数据类型示例
basic_data = {
'int': 42, # 整数
'float': 3.14, # 浮点数
'str': 'Hello Pickle', # 字符串
'list': [1, 2, 3], # 列表
'dict': {'a': 1, 'b': 2}, # 字典
'tuple': (4, 5, 6), # 元组
'bool': True, # 布尔值
'none': None # None值
}
3.2 高级数据类型示例
import datetime
# 自定义类示例
class Person:
def __init__(self, name, age, birthday):
self.name = name
self.age = age
self.birthday = birthday
self._private_attr = "这是私有属性"
def greet(self):
return f"Hello, I'm {self.name}!"
# 创建实例并序列化
person = Person("张三", 25, datetime.datetime(1998, 5, 15))
with open('person.pkl', 'wb') as f:
pickle.dump(person, f)
# 反序列化并访问对象方法
with open('person.pkl', 'rb') as f:
loaded_person = pickle.load(f)
print(f"姓名: {loaded_person.name}")
print(f"年龄: {loaded_person.age}")
print(f"生日: {loaded_person.birthday}")
print(f"问候语: {loaded_person.greet()}")
4. 协议版本
pickle 支持不同的协议版本,每个版本都有其特点:
# 协议版本示例
data = {"name": "李四", "age": 30}
# 测试不同协议版本
for protocol in range(6): # 0-5 协议版本
bytes_data = pickle.dumps(data, protocol=protocol)
print(f"协议版本 {protocol} 序列化后的字节长度:", len(bytes_data))
协议版本特点:
- 协议 0:ASCII 协议,人类可读,兼容旧版本
- 协议 1:老式二进制协议,比协议 0 更高效
- 协议 2:支持新式类,添加了对象引用支持
- 协议 3:支持 bytes 对象,Python 3.x 的默认协议
- 协议 4:支持大对象,更高效的序列化
- 协议 5:支持带外数据和更快的序列化
5. 高级特性
5.1 序列化多个对象示例
# 序列化多个不同类型的对象
obj1 = ["apple", "banana", "orange"]
obj2 = {"x": 100, "y": 200}
obj3 = datetime.datetime.now()
# 写入多个对象
with open('multiple_objects.pkl', 'wb') as f:
pickle.dump(obj1, f)
pickle.dump(obj2, f)
pickle.dump(obj3, f)
# 读取多个对象
with open('multiple_objects.pkl', 'rb') as f:
loaded_obj1 = pickle.load(f)
loaded_obj2 = pickle.load(f)
loaded_obj3 = pickle.load(f)
print("列表对象:", loaded_obj1)
print("字典对象:", loaded_obj2)
print("日期对象:", loaded_obj3)
5.2 异常处理示例
# 文件不存在的异常处理
try:
with open('not_exists.pkl', 'rb') as f:
data = pickle.load(f)
except FileNotFoundError:
print("文件不存在错误被捕获")
# 损坏数据的异常处理
try:
pickle.loads(b'invalid data')
except pickle.UnpicklingError:
print("反序列化错误被捕获")
6. 安全注意事项
-
安全风险
- pickle 数据可能包含恶意代码
- 永远不要 unpickle 不信任来源的数据
- pickle 数据可能执行任意代码
-
最佳实践
- 只处理可信来源的 pickle 数据
- 考虑使用 JSON 等更安全的格式
- 实现数据验证机制
7. 使用场景
适合使用 pickle 的场景:
- 在 Python 程序间传递复杂数据结构
- 保存程序状态
- 缓存计算结果
- 实现对象持久化
- 序列化自定义类实例
不适合使用 pickle 的场景:
- 需要跨语言交互
- 处理不信任的数据
- 需要长期存储(因版本兼容性问题)
- 需要手动编辑序列化数据
8. 与其他序列化方案对比
-
JSON
- 优点:跨语言、可读性好、安全
- 缺点:只支持基本数据类型
- 使用场景:Web API、配置文件
-
Marshal
- 优点:更快、更轻量
- 缺点:功能受限
- 使用场景:Python 内部序列化
-
YAML
- 优点:可读性最好、配置文件友好
- 缺点:速度较慢
- 使用场景:配置文件、数据交换
9. 最佳实践
-
文件操作
# 推荐使用 with 语句处理文件 with open('data.pkl', 'wb') as f: pickle.dump(data, f)
-
性能优化
# 使用最新协议版本获得最佳性能 pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
-
错误处理
try: with open('data.pkl', 'rb') as f: data = pickle.load(f) except (pickle.UnpicklingError, AttributeError, EOFError, ImportError) as e: print(f"反序列化错误: {e}") except FileNotFoundError: print("文件不存在")
-
安全建议
- 实现数据验证机制
- 限制反序列化时的资源使用
- 考虑使用
copyreg
注册安全的类型 - 在处理不信任数据时使用 JSON 替代