Python对象序列化有明确边界:json仅支持基本类型且安全通用,pickle功能强但限于Python环境且有安全风险;含文件句柄、线程锁等对象不可直接序列化;应依场景选方案,避免越界误用。

Python对象序列化不是万能的,它有明确的适用边界和典型场景。用对地方能大幅提升开发效率,用错地方反而引发安全、性能或兼容性问题。
哪些对象可以被安全序列化
Python内置类型(如字典、列表、字符串、数字、None)和简单自定义类实例(不含可调用属性、文件句柄、线程锁等)通常可被pickle或json处理。
- json只支持:dict、list、str、int、float、bool、None —— 且key必须是字符串
- pickle支持更多(如函数、类、带状态的对象),但仅限Python环境间交换,且反序列化存在执行任意代码风险
- 含
lambda、open()返回的文件对象、threading.Lock、数据库连接等,基本无法直接序列化
典型可用场景与对应方案
不同场景需匹配不同序列化方式,不能一概而用:
-
跨进程/网络传递简单数据:用
json(安全、通用、人可读),比如Flask API返回值、HTTP请求体 -
Python内部缓存或临时持久化:用
pickle(保留类型和方法),比如joblib缓存训练好的sklearn模型 -
配置或用户偏好存储:用
json或toml(结构清晰、易编辑),避免用pickle——防止配置文件被恶意篡改触发代码执行 -
高并发服务间通信:考虑
msgpack或protobuf(体积小、解析快),比json更高效,比pickle更安全
常见越界误用及后果
忽视序列化边界容易导致运行时错误或隐患:
立即学习“Python免费学习笔记(深入)”;
- 试图用
json.dumps()序列化datetime对象 → 报TypeError;需预处理(如转为ISO字符串)或用default参数定制 - 用
pickle保存带闭包或局部函数的对象 → 反序列化失败,因依赖的命名空间不可见 - 将含数据库游标或socket连接的对象塞进Redis缓存 → 序列化可能“成功”,但还原后对象已失效,后续调用直接崩溃
- 在不受信输入上使用
pickle.load()→ 攻击者可构造恶意字节流,执行任意系统命令
替代思路:不序列化,也能传状态
当对象本身难以序列化时,优先考虑“传描述,不传实体”:
- 不缓存整个DataFrame,而缓存其路径+读取参数(如
{"path": "data.parquet", "columns": ["a","b"]}) - 不序列化类实例,而记录初始化所需的关键参数(如
{"class": "MyModel", "params": {"lr": 0.01}}),用工厂函数重建 - 对复杂对象提供
__getstate__/__setstate__方法,显式控制哪些字段参与pickle,排除不可序列化部分
序列化是工具,不是目的。判断一个对象要不要、能不能、该用哪种方式序列化,关键看它要流向哪里、由谁还原、是否可信、是否长期存储。清楚边界,才能用得稳、用得准。










