Python 序列化
Python序列化是将数据对象转换为可存储或传输的格式(如字节流或字符串)的过程,反序列化则是将其转换回原始对象。Python提供了多种序列化方法,包括内置的pickle模块和json模块。本章节将详细介绍序列化的概念、Python中的序列化工具,以及如何使用pickle和json实现序列化与反序列化。
1. 什么是序列化?
序列化(Serialization)是将内存中的对象转换为字节流或文本格式,以便存储到文件或通过网络传输。反序列化(Deserialization)则是将这些字节流或文本格式转换回内存中的对象。序列化的主要用途包括:
- 数据持久化:将对象保存到文件中,以便稍后恢复。
- 数据传输:在网络中传输对象,例如在分布式系统中。
- 缓存:将复杂对象保存为文件,减少重复计算。
Python中常用的序列化模块包括pickle
(用于二进制序列化)和json
(用于文本序列化)。两者各有特点,适用于不同场景。
2. Pickle模块:二进制序列化
pickle
是Python内置的模块,支持几乎所有Python对象的序列化,包括自定义类、函数等。它将对象转换为字节流,适合高效存储和传输,但不适合跨语言或安全性要求高的场景。
2.1 Pickle的基本用法
pickle
提供以下核心函数:
pickle.dump(obj, file)
:将对象序列化并写入文件。pickle.dumps(obj)
:将对象序列化为字节对象。pickle.load(file)
:从文件中反序列化对象。pickle.loads(bytes)
:从字节对象反序列化。
以下是一个完整的示例,展示如何使用pickle
保存和加载数据:
import pickle
# 定义数据
data = {
"name": "张三",
"age": 30,
"scores": [85, 90, 95]
}
# 序列化到文件
with open("data.pkl", "wb") as file:
pickle.dump(data, file)
# 从文件反序列化
with open("data.pkl", "rb") as file:
loaded_data = pickle.load(file)
print(loaded_data)
运行结果:
{'name': '张三', 'age': 30, 'scores': [85, 90, 95]}
注意事项:
- 文件操作时,
dump
和load
需要使用二进制模式("wb"
和"rb"
)。 pickle
序列化的数据是二进制格式,不适合直接阅读。
2.2 序列化自定义对象
pickle
支持序列化自定义类对象。以下是一个序列化自定义类的示例:
import pickle
# 定义一个类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Person(name={self.name}, age={self.age})"
# 创建对象
person = Person("李四", 25)
# 序列化到文件
with open("person.pkl", "wb") as file:
pickle.dump(person, file)
# 从文件反序列化
with open("person.pkl", "rb") as file:
loaded_person = pickle.load(file)
print(loaded_person)
运行结果:
Person(name=李四, age=25)
2.3 Pickle的安全性问题
pickle
在反序列化时可能执行恶意代码,因此不要反序列化不受信任的来源数据。例如,从未知来源的文件或网络加载pickle
数据可能导致安全风险。
3. JSON模块:文本序列化
json
模块用于将Python对象序列化为JSON格式(字符串),适合跨语言传输和人类可读的场景。JSON支持的数据类型有限,包括:
- 基本类型:字符串、数字、布尔值、
None
- 容器类型:列表、字典
- 不支持复杂对象(如自定义类、函数)
3.1 JSON的基本用法
json
模块提供以下核心函数:
json.dump(obj, file)
:将对象序列化并写入文件。json.dumps(obj)
:将对象序列化为JSON字符串。json.load(file)
:从文件中反序列化JSON数据。json.loads(string)
:从JSON字符串反序列化。
以下是一个完整示例:
import json
# 定义数据
data = {
"name": "王五",
"age": 28,
"scores": [80, 85, 90],
"is_student": True,
"comment": None
}
# 序列化到文件
with open("data.json", "w", encoding="utf-8") as file:
json.dump(data, file, ensure_ascii=False, indent=4)
# 从文件反序列化
with open("data.json", "r", encoding="utf-8") as file:
loaded_data = json.load(file)
print(loaded_data)
运行结果:
{'name': '王五', 'age': 28, 'scores': [80, 85, 90], 'is_student': True, 'comment': None}
注意事项:
ensure_ascii=False
确保中文字符不被转义,保持可读性。indent=4
使输出的JSON文件格式化,易于阅读。- 文件操作需要指定
encoding="utf-8"
以支持中文。
3.2 序列化自定义对象
JSON不支持直接序列化自定义对象,但可以通过自定义编码器来实现。以下是一个示例:
import json
# 定义一个类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 自定义JSON编码器
class PersonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age}
return super().default(obj)
# 创建对象
person = Person("赵六", 22)
# 序列化为JSON字符串
json_str = json.dumps(person, cls=PersonEncoder, ensure_ascii=False)
print(json_str)
# 反序列化(需要手动转换)
loaded_data = json.loads(json_str)
print(loaded_data)
运行结果:
{"name": "赵六", "age": 22}
{'name': '赵六', 'age': 22}
注意:反序列化后,得到的是字典,而不是Person
对象。如需恢复为对象,需要额外处理。
4. Pickle与JSON的比较
以下是pickle
和json
的对比,帮助选择合适的序列化工具:
特性 | Pickle | JSON |
---|---|---|
格式 | 二进制 | 文本(字符串) |
可读性 | 不可读 | 人类可读 |
支持的数据类型 | 几乎所有Python对象(包括自定义类) | 基本类型、列表、字典 |
跨语言支持 | 仅限Python | 跨语言支持 |
安全性 | 不安全(可能执行恶意代码) | 安全 |
性能 | 更快(二进制) | 稍慢(文本解析) |
使用场景 | Python内部数据存储、缓存 | 跨平台数据交换、配置文件 |
选择建议:
- 如果数据仅在Python中使用,且需要序列化复杂对象,选择
pickle
。 - 如果需要跨语言传输或人类可读的格式,选择
json
。
5. 高级话题:序列化的其他工具
除了pickle
和json
,Python生态中还有其他序列化工具,适用于特定场景:
shelve
:基于pickle
,提供类似字典的持久化存储,适合简单键值存储。marshal
:Python内部使用的序列化模块,效率高但不适合常规开发。yaml
:通过pyyaml
库支持,适合复杂配置文件,类似JSON但更灵活。msgpack
:高效的二进制序列化库,适合高性能场景。
以下是一个简单的shelve
示例:
import shelve
# 存储数据
with shelve.open("mydata") as db:
db["user"] = {"name": "陈七", "age": 27}
# 读取数据
with shelve.open("mydata") as db:
user = db["user"]
print(user)
运行结果:
{'name': '陈七', 'age': 27}
6. 最佳实践与注意事项
- 安全性:避免使用
pickle
反序列化不受信任的数据,优先考虑json
。 - 编码:处理JSON时,始终指定
encoding="utf-8"
以支持多语言。 - 错误处理:序列化和反序列化时,添加异常处理以应对文件错误或格式问题。
- 版本兼容性:
pickle
在不同Python版本间可能不兼容,注意版本一致性。 - 性能优化:对于大数据量,考虑
msgpack
或压缩序列化结果。
以下是一个带错误处理的json
示例:
import json
try:
# 尝试加载JSON文件
with open("data.json", "r", encoding="utf-8") as file:
data = json.load(file)
print(data)
except FileNotFoundError:
print("文件不存在!")
except json.JSONDecodeError:
print("JSON格式错误!")