pickle不能直接存datetime或自定义类实例,因其仅序列化属性和模块路径而不保存类定义,加载时若类未定义或已变更则报错;json不支持非原生类型需用default参数转换;pickle通常比json更快更小,但跨环境应优先选json加类型契约。

为什么 pickle 不能直接存 datetime 或自定义类实例?
因为 pickle 默认只序列化对象的属性和模块路径,不保存类定义本身。如果加载时当前环境没有导入对应类、或类定义已变更,UnpicklingError 或 AttributeError 就会立刻出现。比如保存了 datetime.now() 的对象,加载时没问题;但若你用的是自定义类 class Report:,而加载脚本里没定义它,pickle.load() 就会报 AttributeError: Can't get attribute 'Report' on <module></module>。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 确保保存与加载使用同一 Python 版本(尤其注意 Python 3.8+ 对
Protocol类的处理变化) - 避免跨项目共享 pickle 文件——它不是稳定格式,只适合同一代码基内部短期暂存
- 如必须用自定义类,可在类定义前加
__reduce__方法控制序列化行为,但多数情况不如改用json+ 显式转换
json.dumps() 报错 TypeError: Object of type X is not JSON serializable 怎么办?
这是 json 最常见的拦路虎:json 只认 str、int、float、bool、None、list、dict 这七种原生类型,其余都得手动转。比如 datetime、set、numpy.ndarray、Decimal 全部被拒。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
default=参数传入转换函数,例如:json.dumps(data, default=lambda o: o.isoformat() if hasattr(o, 'isoformat') else str(o))
- 对
set,先转成list;对bytes,用.decode('utf-8')或 base64 编码 - 别依赖
json.JSONEncoder子类——它容易在嵌套结构中漏掉某一层,不如用default函数直截了当
保存大字典或嵌套列表时,pickle 和 json 哪个更快、更小?
实测结论:对纯 Python 原生数据(dict/list/str 等),pickle(协议 5)通常比 json 快 1.5–3 倍,体积小 10%–25%;但一旦含 numpy 数组或大量重复字符串,差距会拉大——这时该换 joblib 或 feather,而不是硬撑 pickle。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
pickle.HIGHEST_PROTOCOL(Python 3.8+ 默认是 5),别用默认协议 3 —— 它慢且不支持共享字符串引用 - json 输出可加
separators=(',', ':')去空格,减小体积;但别开sort_keys=True,它会让性能掉 20%+ - 若数据含二进制字段(如图像 base64 字符串),json 反而更稳——pickle 对长 bytes 对象有内存峰值问题
如何安全地把 dict 带 datetime 保存为文件并重载?
最简可行方案是统一转成 ISO 字符串再进 json,加载时按需解析。不推荐用 pickle,除非你确定永不跨环境、不升级类结构。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 保存:
import json from datetime import datetime data = {'created': datetime.now(), 'items': ['a', 'b']} json.dump({k: (v.isoformat() if isinstance(v, datetime) else v) for k, v in data.items()}, open('data.json', 'w')) - 加载:
loaded = json.load(open('data.json')) if 'created' in loaded: loaded['created'] = datetime.fromisoformat(loaded['created']) - 更通用的做法:封装一个
smart_dump()/smart_load(),内置常见类型映射表(datetime、date、Decimal),避免每次重复写逻辑
真正麻烦的从来不是“怎么存”,而是“下次读的时候,谁还记得这个字段当初是 datetime?”——所以关键不是选 pickle 还是 json,是在数据进出时留下可追溯的类型契约。


















