用 pickle.dump() 保存字典需以 "wb" 模式打开文件并指定 protocol=2 提高兼容性;含不可序列化对象(如锁、文件句柄)会报 TypeError;自定义类需确保 dict 干净或实现 __getstate__/__setstate__;加载时须用 "rb" 模式配 pickle.load(),且类定义必须已导入。

用 pickle.dump() 保存字典到文件,但要注意协议版本
直接写入最常用,但默认协议(Python 3.8+ 是 protocol 4)可能在旧 Python 版本里打不开。如果目标环境不确定,显式指定 protocol=2 更稳妥——它兼容 Python 2.7 到 3.x,只是不支持某些新类型(比如带循环引用的嵌套对象)。
常见错误现象:UnicodeDecodeError 或 EOFError,往往是因为没用二进制模式打开文件。
- 必须用
open(..., "wb")(不是"w"),否则报错 - 字典含不可序列化对象(如
threading.Lock、文件句柄、lambda)会直接抛TypeError - 若字典键是自定义类实例,该类需有可被 pickle 的状态(通常要求所有属性都是基本类型或可 pickle 对象)
import pickle
data = {"name": "alice", "scores": [95, 87]}
with open("data.pkl", "wb") as f:
pickle.dump(data, f, protocol=2)用 pickle.dumps() 序列化对象再手动写入,适合需要加密或压缩的场景
它返回 bytes,不碰文件系统,给你完全控制权。比如你想先用 zlib 压缩再存,或者用 cryptography 加密后写磁盘,就必须走这一步。
性能影响:相比 dump() 直接写文件,多一次内存拷贝;但换来的是灵活性——你可以把结果存在 Redis、发 HTTP 请求、拼进 ZIP 包。
立即学习“Python免费学习笔记(深入)”;
-
pickle.dumps(obj)默认用最高协议,若要兼容老环境,得传protocol=2 - 别用
str(pickle.dumps(...))转字符串——那会破坏二进制结构,读取时直接UnpicklingError - 若对象很大,
dumps()会一次性占满内存;超大对象建议用dump()配合分块或流式处理
import pickle
obj = {"config": {"timeout": 30}}
serialized = pickle.dumps(obj, protocol=2)
# 后续可加密、压缩、base64 编码等
with open("safe.bin", "wb") as f:
f.write(serialized)加载时用 pickle.load() 读文件,但必须和保存时用相同模式
对应 dump() 就得用 load(),对应 dumps() 就得用 loads()。混用会出错,比如用 loads() 去读文件对象,会报 TypeError: a bytes-like object is required。
容易踩的坑:文件路径错、权限不够、文件被其他进程锁住,都会导致 FileNotFoundError 或 OSError;更隐蔽的是文件内容被截断或损坏,此时抛 EOFError 或 UnpicklingError。
- 务必用
open(..., "rb")打开,否则load()读不到有效字节流 - 若保存时用了
protocol=2,加载时无需指定协议——load()自动识别 - 反序列化不受信任的数据极其危险,
pickle可执行任意代码;生产环境绝不要加载来源不明的.pkl文件
import pickle
with open("data.pkl", "rb") as f:
data = pickle.load(f) # 不是 pickle.loads(f)自定义类实例能被 pickle 的关键条件:__dict__ 可控且无不可序列化成员
不是所有类都能直接 pickle.dump()。核心看两点:实例的 __dict__ 是否干净,以及类是否定义了 __getstate__/__setstate__ 来干预序列化过程。
典型失败场景:类里存了 sqlite3.Connection、socket.socket、闭包函数、__slots__ 但没实现 __getstate__。
- 最简方案:确保所有实例属性都是基本类型、列表、字典、其他可 pickle 类的实例
- 若必须存不可序列化对象(如缓存、连接),在
__getstate__里删掉它们(返回self.__dict__.copy()并 pop 掉敏感 key) - 类方法、类变量、模块级变量不会被保存;只有实例
__dict__中的内容参与序列化
class Config:
def __init__(self, path):
self.path = path
self._cache = {} # 不可 pickle,需排除
def __getstate__(self):
state = self.__dict__.copy()
state.pop("_cache", None)
return state反序列化逻辑依赖类定义在当前运行环境中已导入,哪怕只是空类声明;否则会报 AttributeError: Can't get attribute 'Config' on <module '<strong>main</strong>'>。这点常被忽略,尤其在分布式任务或跨脚本加载时。










