定义__slots__后直接赋值未声明属性会报AttributeError;若需动态添加,须显式包含'__dict__';继承时父类无__slots__则子类定义无效;其核心是优化内存与性能,非强制封禁属性。

定义 __slots__ 后直接赋值新属性会报错
不能。一旦类中定义了 __slots__,Python 就会禁用默认的 __dict__,实例只能拥有 __slots__ 中声明的那些属性。尝试给未声明的属性赋值,会触发 AttributeError:
class Person:
__slots__ = ['name', 'age']
p = Person()
p.name = 'Alice' # ✅ 允许
p.age = 30 # ✅ 允许
p.email = 'a@b.c' # ❌ AttributeError: 'Person' object has no attribute 'email'
想临时加属性?得显式提供 __dict__
如果确实需要动态添加属性(比如调试、临时打补丁),必须在 __slots__ 中**显式包含 '__dict__'**。这样 Python 会为实例保留 __dict__,允许动态设置任意属性:
-
__slots__ = ['name', 'age', '__dict__']→ 动态属性可用,但内存开销略增 - 不加
'__dict__'就彻底禁止,连setattr(p, 'x', 1)都失败 - 注意:
__dict__只影响实例,不影响类本身的属性查找逻辑
__slots__ 和继承一起用时更易踩坑
子类若也定义 __slots__,它只会限制子类新增的属性;父类的 __slots__ 仍生效。但如果父类没定义 __slots__,子类加了也没用——因为父类实例已有 __dict__,子类实例自动继承它:
- 父类有
__slots__,子类没写 → 子类实例仍受父类__slots__限制 - 父类没
__slots__,子类写了 → 实际无效,子类实例仍可动态加属性 - 双方都定义,且子类想扩展 → 必须确保父类没
__dict__,否则约束被绕过
性能与设计意图比“能不能加”更重要
__slots__ 的核心目的不是“封死属性”,而是节省内存和加速属性访问。如果你频繁需要动态加属性,说明这个类可能不适合用 __slots__ —— 它更适合结构稳定、实例量大的场景(比如 ORM 模型、数据容器)。强行加 '__dict__' 会让优化失效,还可能掩盖设计问题。
真正容易被忽略的是:__slots__ 不影响类属性、也不阻止通过 __setattr__ 拦截并自定义逻辑,但那属于另一层控制,和“能否直接赋值”是两回事。










