常见原因是类中定义了__slots__但__getstate__未显式处理其属性,导致pickle尝试访问不存在的__dict__而抛AttributeError。

为什么 __getstate__ 返回字典却仍报 AttributeError?
常见原因是类中定义了 __slots__,但 __getstate__ 没有显式处理 __slots__ 中的属性。Pickle 默认尝试访问 self.__dict__,而启用 __slots__ 后该属性不存在,直接抛 AttributeError: 'MyClass' object has no attribute '__dict__'。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 若类用了
__slots__,__getstate__必须返回一个普通字典,且键必须是__slots__中声明的属性名(不包括未赋值的) - 不要在
__getstate__里直接返回self.__dict__—— 它根本不存在 - 可手动构造状态字典:
def __getstate__(self): state = {} for slot in self.__slots__: if hasattr(self, slot): state[slot] = getattr(self, slot) return state
如何安全排除不可序列化的属性(比如文件句柄、线程锁)?
直接在 __getstate__ 中过滤掉非基本类型或不可序列化对象,比依赖 __reduce_ex__ 更直观可控。否则在反序列化时可能因残留引用导致 AttributeError 或运行时错误。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
isinstance(..., (io.IOBase, threading.Lock, types.FunctionType))判断典型不可序列化类型 - 跳过以
_开头的私有属性(除非明确需要),避免意外包含闭包或绑定方法 - 示例:
def __getstate__(self): state = {k: v for k, v in self.__dict__.items() if not isinstance(v, (io.TextIOWrapper, threading.Lock))} # 若用了 __slots__,改用 slot 迭代 + hasattr 判断
继承自内置类型(如 list、dict)的类为何总出错?
这类子类默认没有 __dict__,且父类的序列化逻辑会绕过你的 __getstate__,直接调用其内部 C 层实现,导致你自定义的状态逻辑被忽略,反序列化后属性丢失,后续访问就触发 AttributeError。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 显式覆盖
__reduce_ex__,完全接管序列化流程 - 返回元组
(cls, (args,), state),其中args是用于重建实例的参数(如list子类传list(self)),state是附加属性字典 - 务必确保
__init__能接受这些args,否则反序列化会失败
__setstate__ 里访问不存在的属性会静默失败吗?
不会静默——它会在反序列化末尾执行,此时对象已创建但属性尚未设置。如果代码里写了 self.xxx = state['xxx'],而 state 里没 'xxx',就会立刻抛 KeyError;但如果写成 self.xxx = state.get('xxx'),值为 None,后续访问 self.xxx 可能触发 AttributeError(取决于是否在 __slots__ 中声明)。
实操建议:
立即学习“Python免费学习笔记(深入)”;
-
__setstate__中对每个预期字段做存在性检查,缺失时设默认值或跳过 - 若类用
__slots__,必须确保所有要恢复的字段都在其中声明,否则setattr(self, k, v)会直接报AttributeError - 别省略
__setstate__:即使逻辑简单,也要显式定义,防止父类逻辑干扰
复杂点在于,Pickle 的错误往往不指向真正出问题的那行代码,而是暴露在反序列化后的第一次属性访问时。最容易被忽略的是:你以为只改了 <strong>getstate</strong> 就够了,但 <strong>setstate</strong> 没同步适配,或者 <strong>slots</strong> 和状态字典字段没对齐。


















