定义 __slots__ 后 weakref.ref 仍可正常工作,只要未显式禁用弱引用:Python 自动为 __weakref__ 预留位置,无需且不可将其写入 __slots__ 元组,否则触发 TypeError。

定义 __slots__ 后 weakref.ref 仍可正常工作
只要类没有显式禁用弱引用(即未定义 __weakref__ 且未将其从 __slots__ 中排除),weakref.ref 就能正常使用。Python 在生成 __slots__ 类时,会自动为 __weakref__ 预留位置——前提是它没被用户手动写进 __slots__ 列表里,也没被显式设为 None。
常见错误现象:创建 weakref.ref(obj) 后调用立即返回 None,或抛出 TypeError: cannot create weak reference to 'X' object。
- 检查是否在
__slots__中漏写了'__weakref__'—— 不需要加,也不该加;Python 会自动处理 - 确认没在类定义中写
__weakref__ = None或类似赋值,这会覆盖默认行为 - 若继承自父类,确保父类也没禁用弱引用(比如父类定义了空
__slots__ = ()且没留__weakref__)
__slots__ = ('__weakref__', ...) 是错误写法
手动把 '__weakref__' 写进 __slots__ 元组,会导致运行时报错:TypeError: __weakref__ slot must be at the end(CPython 实现限制)。这不是规范要求,而是底层 C 层对 slot 偏移量的硬性约束。
正确做法是完全不提 __weakref__,让 Python 自动注入:
class A:
__slots__ = ('x', 'y') # ✅ 正确:__weakref__ 自动可用
错误示例:
class B:
__slots__ = ('x', '__weakref__') # ❌ TypeError
- 即使顺序对(如
('__weakref__', 'x')),也会因内部 slot 排序逻辑失败 - 某些旧版本 Python(如 3.7 之前)可能静默忽略,但行为不可靠,不建议依赖
继承链中 __weakref__ 的传递规则
弱引用支持沿继承链向上查找;只要任意一层父类允许弱引用(即未禁用),子类实例就支持 weakref。
- 父类定义
__slots__ = ()→ 默认不提供__weakref__,子类必须自己“激活”:要么不定义__slots__,要么确保某层有非空__slots__且未干扰__weakref__ - 父类没定义
__slots__→ 实例自带__dict__和__weakref__,子类加__slots__不影响弱引用(除非子类主动破坏) - 多继承时,只要有一个父类“贡献”了
__weakref__支持,就足够
验证弱引用是否生效的最小检查方式
别只看 weakref.ref(obj) 是否抛异常,要真正测试引用是否可被回收后失效:
import weakrefclass C: slots = ('value',)
obj = C() obj.value = 42 r = weakref.ref(obj) assert r() is obj # ✅ 活着时能取回
del obj assert r() is None # ✅ 回收后返回 None,说明 weakref 生效
容易被忽略的是:如果测试中对象被全局变量、调试器或 locals() 意外持有,r() 就不会变 None,误判为 weakref 失效。










