json.dumps()输出跨语言的可读JSON字符串,仅支持7种基础类型;pickle.dumps()输出Python专用二进制流,支持几乎所有对象但有反序列化安全风险且不跨版本兼容。

json.dumps() 和 pickle.dumps() 的核心差异在哪
根本区别不在“能不能转”,而在“转成什么、给谁用”。json.dumps() 输出标准 JSON 字符串,人类可读、跨语言通用;pickle.dumps() 输出 Python 专用二进制字节流,只保证在同版本 Python 中能还原原对象,不兼容其他语言,也不保证跨 Python 版本安全。
常见错误现象:TypeError: Object of type set is not JSON serializable —— 这说明你试图用 json.dumps() 序列化 set、datetime、自定义类实例等非基础类型,而 pickle 默认就能处理这些(除非对象含不可持久化的状态,如文件句柄)。
-
json只支持dict、list、str、int、float、bool、None这七种类型及其嵌套 -
pickle支持几乎所有 Python 对象,但反序列化时会执行任意代码(__reduce__等钩子),有严重安全风险,绝不能加载不可信数据 - 性能上,
pickle通常比json快 2–5 倍(尤其对复杂嵌套结构),但生成的字节流体积更大
什么时候必须用 json,什么时候只能用 pickle
选 json 不是“更安全”的权衡,而是场景硬性要求:只要数据要出 Python 进浏览器、进 Node.js、进 Java 后端、进数据库的 JSON 字段(如 PostgreSQL 的 JSONB)、或需要人工调试/审查内容,就必须用 json。
选 pickle 是“别无选择”的妥协:比如缓存一个带方法绑定的 threading.Lock、保存 numpy.ndarray(虽有更优方案如 np.save)、或快速暂存训练中的 sklearn 模型到磁盘供同一脚本下次加载——此时你不需要跨语言,也不关心内容是否可读,只求快且保真。
立即学习“Python免费学习笔记(深入)”;
- Web API 响应体、前端 localStorage 存储、配置文件 → 强制用
json - Redis 缓存 Python 函数闭包、临时保存
torch.nn.Module实例 → 只能用pickle(但建议优先考虑torch.save等专用方案) - 日志中记录结构化事件?用
json;记录调试用的完整栈帧对象?pickle是唯一现实选项(尽管不推荐)
json 处理 datetime 或自定义类的绕不过去的坑
json.dumps() 报 TypeError: Object of type datetime is not JSON serializable 是高频问题,不是 bug,是设计使然。它不提供默认转换逻辑,必须显式干预。
最简方案是传 default 参数:
import json from datetime import datetimedata = {"time": datetime.now(), "value": 42} json.dumps(data, default=str) # → '{"time": "2024-06-12T15:23:45.123456", "value": 42}'
但 default=str 是“暴力转字符串”,丢失类型信息,反序列化时得靠业务逻辑再解析。更严谨的做法是定义专用 encoder:
- 继承
json.JSONEncoder,重写default()方法,对datetime返回isoformat(),对bytes返回base64.b64encode(...).decode() - 反序列化时,用
object_hook回调识别特定 key(如"__datetime__")并还原为datetime - 不要试图让
json原生支持set:序列化前转list,反序列化后转回set,这是最清晰可控的方式
pickle.load() 加载不可信数据等于执行远程代码
这是被反复警告却仍被踩爆的致命点。pickle 反序列化过程会动态调用类构造器、__setstate__、甚至 __reduce__ 返回的任意可调用对象。攻击者可构造恶意字节流,在 pickle.load() 时触发 os.system("rm -rf /")。
没有“安全模式”开关。所谓 safe=True 是不存在的 API。唯一防御手段是:绝不加载来源不明的 pickle 数据。
- 如果你控制数据生产端和消费端,且确定永远只在可信环境(如单机离线脚本)中使用,
pickle可用 - 任何涉及网络传输、用户上传、第三方 SDK 返回的数据,一律禁止
pickle.load() - 替代方案:用
json+ 显式类型转换;或用msgpack(更快更小,但仍是 Python-centric,且同样不解决安全问题);真正需要高性能+安全时,选protobuf或capnproto
复杂点在于:很多人以为“我只用 pickle 存自己代码里的对象,肯定安全”,却忽略了依赖库可能悄悄把用户输入塞进某个会被 pickle 序列化的容器里——这种隐式污染极难审计。











