该用 json.dumps() 时:数据结构简单且需跨语言或人工可读;否则用 pickle.dump()。json 不支持 datetime 等类型,pickle 可存任意 python 对象但不安全、不可跨语言。

什么时候该用 json.dumps(),而不是 pickle.dump()
JSON 是跨语言、可读、安全的序列化格式;Pickle 是 Python 专属、可存任意对象、但有执行风险。选 JSON 的前提是:数据结构简单(dict、list、str、int、float、bool、None),且需要被其他语言读取或人工查看。
- 遇到
TypeError: Object of type X is not JSON serializable,说明你试图序列化datetime、set、自定义类实例等 —— 这是 JSON 的硬限制,不是写法问题 - 如果只是临时存 Python 进程间数据(比如缓存函数结果),又含
numpy.ndarray或带方法的对象,pickle是更直接的选择 -
json默认不保留顺序(Python 3.7+dict有序,但json不保证输出顺序);pickle完全保留对象状态,包括私有属性和内存地址相关行为(如循环引用)
json.load() 报 JSONDecodeError: Expecting value 怎么快速定位
这个错误几乎都来自输入内容为空、只有空白符,或混入了 BOM、注释、非 UTF-8 字节 —— JSON 标准不允许这些。
- 先用
open(file, "rb").read()看前 20 字节,确认有没有b"\xef\xbb\xbf"(UTF-8 BOM);有就改用encoding="utf-8-sig" - 别直接
json.load(f),先f.read().strip(),空字符串就跳过,避免把日志文件末尾的空行当 JSON 解析 - 浏览器或 curl 保存的响应体可能含 HTML 标签或重定向提示,用
filetype库或简单检查是否以{或[开头
pickle 反序列化时为什么有时能跑,有时报 AttributeError: Can't get attribute 'X' on <module></module>
这是 pickle 的模块绑定机制导致的:它只存类名和模块路径,反序列化时会尝试从当前运行环境的 __main__ 或对应模块里重新导入该类。一旦类定义位置变了,就找不到。
- 把要 pickle 的类定义在独立 `.py` 文件中(比如
models.py),不要放在脚本顶层或 Jupyter cell 里 - 避免用
lambda、嵌套函数、functools.partial等动态生成的对象 —— 它们没有稳定模块路径 - 生产环境慎用
pickle做持久化存储;升级代码后旧 pickle 文件大概率失效,比数据库迁移还难处理
性能和大小:JSON 和 Pickle 在大数据量下到底差多少
实测 10 万条 {"id": int, "name": str, "score": float} 的字典列表,json.dumps() 比 pickle.dumps(..., protocol=4) 慢约 1.5–2 倍,体积大 30%–50%,但差异随数据嵌套深度增加而收窄。
立即学习“Python免费学习笔记(深入)”;
-
pickle的protocol=5(Python 3.8+)支持缓冲区零拷贝,对大bytes或array.array有明显优势;JSON 始终走字符串编码 - 如果数据含大量重复 key(如日志字段固定),用
ujson或orjson可提速 3–5 倍,但它们不兼容所有 JSON 标准(比如orjson不支持default参数) - 别为了省几 MB 自动切到
pickle—— 调试成本、跨环境风险、长期可维护性损失远高于磁盘开销
真正麻烦的从来不是选哪个函数,而是同一个项目里混用两种序列化方式:比如用 JSON 存配置、Pickle 存缓存,结果某天有人把缓存文件误当配置加载,或者用 json.loads() 去读 pickle 二进制 —— 错误信息不会告诉你“你读错了格式”,只会抛一堆字节解码异常。










