Python 中 pickle 和 json 序列化有什么区别?
简化版
json 是跨语言文本格式,适合接口传输和配置;pickle 是 Python 专用二进制序列化,能保存更多 Python 对象,但不安全,不能反序列化不可信数据。面试重点是兼容性、安全性和可读性差异。
详细版
JSON 示例:
import json
data = {"name": "Tom", "age": 18}
text = json.dumps(data, ensure_ascii=False)
obj = json.loads(text)
pickle 示例:
import pickle
data = {"name": "Tom", "age": 18}
binary = pickle.dumps(data)
obj = pickle.loads(binary)
区别:
| 对比点 | json | pickle |
|---|---|---|
| 格式 | 文本 | 二进制 |
| 跨语言 | 好 | Python 专用 |
| 可读性 | 可读 | 不适合人工阅读 |
| 支持对象 | 基本数据类型为主 | 支持更多 Python 对象 |
| 安全性 | 相对安全 | 反序列化不可信数据危险 |
| 典型场景 | API、配置、日志 | Python 内部缓存、模型或对象临时保存 |
使用 pickle 最大的红线:不要加载不可信来源的 pickle 数据,因为反序列化可能执行恶意代码。
完整版教学
一、序列化解决什么问题
内存里的对象不能直接写入文件或通过网络传输,需要转换成某种可保存、可传输的格式。
这个过程叫序列化:
object -> bytes/string
反向过程叫反序列化:
bytes/string -> object
Python 常见序列化方式包括 json、pickle、marshal、第三方的 msgpack、protobuf 等。
面试最常考的是 json 和 pickle。
二、json 的特点
JSON 是通用文本格式,跨语言支持很好。
支持的数据类型主要包括:
- object,对应 Python dict;
- array,对应 Python list;
- string;
- number;
- boolean;
- null,对应 Python None。
示例:
import json
text = json.dumps({"ok": True, "items": [1, 2]})
data = json.loads(text)
JSON 很适合接口数据、配置文件、日志数据,因为它可读、通用、容易调试。
三、pickle 的特点
pickle 是 Python 专用序列化协议。
它能处理更多 Python 对象,比如某些自定义类实例:
import pickle
class User:
def __init__(self, name):
self.name = name
u = User("Tom")
data = pickle.dumps(u)
u2 = pickle.loads(data)
但 pickle 的可移植性差。它依赖 Python 对象结构、模块路径和类定义。代码结构变了,旧 pickle 文件可能就无法正常加载。
四、pickle 为什么不安全
pickle 反序列化不是简单读取数据,它可能根据数据指令导入模块、调用对象构造逻辑。
如果攻击者构造恶意 pickle,加载时可能执行危险代码。
所以标准建议非常明确:不要反序列化不可信来源的 pickle 数据。
安全边界外的数据交换,优先用 JSON、protobuf 等更适合传输的格式。
五、json 处理自定义对象
JSON 默认不能直接序列化自定义对象:
json.dumps(User("Tom")) # TypeError
常见做法是先转成 dict:
def to_dict(user):
return {"name": user.name}
json.dumps(to_dict(user), ensure_ascii=False)
或者提供 default 函数:
json.dumps(user, default=lambda obj: obj.__dict__)
工程里更建议显式定义转换逻辑,避免把内部字段不小心暴露出去。
六、如何选择
选择建议:
- 对外接口:JSON;
- 配置文件:JSON 或 YAML;
- 跨语言通信:JSON、protobuf、msgpack;
- Python 内部临时缓存:可以考虑 pickle;
- 不可信数据:不要用 pickle loads;
- 长期存储:谨慎 pickle,因为代码变更会影响兼容性。
pickle 能力强,但边界窄;JSON 能力简单,但生态通用。
七、常见误区与追问
易错点:JSON 是数据交换格式,pickle 是 Python 对象序列化机制。面试里一定要把“跨语言”和“安全性”放在第一层区别里讲。
- 误区:pickle 比 JSON 强,所以优先用 pickle。 pickle 能保存更多 Python 对象信息,但只适合可信 Python 环境;对外接口、配置和跨语言交换应优先 JSON。
- 追问:为什么不能反序列化不可信 pickle? pickle 加载过程可能执行对象构造和还原逻辑,恶意 payload 有机会触发任意代码执行,风险远高于普通数据解析。
- 误区:JSON 能直接保存任意 Python 对象。 JSON 只支持有限数据类型,如对象、数组、字符串、数字、布尔和 null;自定义对象需要转成 dict 或提供自定义 encoder。
- 追问:pickle 的版本兼容有什么问题? pickle 数据依赖 Python 类路径和对象结构,代码重构、类名移动、Python 版本或协议差异都可能导致旧数据无法加载。
- 误区:序列化后内容一定可读可调试。 JSON 文本可读性较好;pickle 是二进制协议,不适合作为人工编辑或跨系统长期存储格式。
- 追问:缓存内部 Python 对象时怎么选? 可信、短生命周期、只在 Python 内部使用时可以考虑 pickle;长期存储、跨服务通信或外部输入应选择 JSON、MessagePack、Protobuf 等更明确的格式。
八、加强记忆
JSON 是跨语言文本数据格式,适合传输和配置;pickle 是 Python 专用对象序列化,适合内部临时保存。最重要的红线是:不要反序列化不可信 pickle。面试回答要同时讲格式、兼容性、支持类型和安全性。