__slots__应在高频创建、属性固定且无需动态赋值的轻量对象中使用,如数据模型或缓存条目;需显式声明所有实例属性,父类与子类均须定义以避免__dict__重建,且不可与__dict__共存。

__slots__ 确实能减少内存占用,但只在类实例数量大、属性固定且不需动态赋值时才值得用;盲目加 __slots__ 可能导致 AttributeError 或破坏继承行为。
什么时候该用 __slots__?
适用于:高频创建的轻量对象(如数据模型、缓存条目、ORM 实体),且明确知道所有属性名,不依赖 __dict__ 动态存取。
- 类定义中显式声明所有允许的实例属性名,例如
__slots__ = ('name', 'age', 'id') - 父类用了
__slots__,子类也必须定义,否则父类的__slots__失效 - 如果需要支持
__dict__(比如用vars()、json.dumps()直接序列化),就别用__slots__ - 使用
__slots__后,无法再给实例赋值未声明的属性,会报AttributeError: 'X' object has no attribute 'xxx'
__slots__ 怎么写才不出错?
常见错误是忽略继承链或误以为它能限制类属性。它只约束实例属性,不影响类变量或方法。
- 子类若没定义
__slots__,Python 会自动创建__dict__,父类的__slots__形同虚设 - 想继承并扩展属性,子类
__slots__应包含父类全部 + 新增项,例如:__slots__ = ('score',) + Parent.__slots__ - 不能和
__dict__共存:一旦定义__slots__,实例就不再有__dict__,所以obj.__dict__会抛AttributeError - 如果要用
weakref,需在__slots__中显式加入'__weakref__'
内存节省效果到底有多大?
不是线性下降,而是去掉每个实例的 __dict__ 字典开销(通常省下 ~56–100 字节/实例),对上万实例才有明显差异。
- 普通类实例:每个实例带一个空
__dict__(约 240 字节) + 属性存储 - 启用
__slots__后:属性直接存为 C 结构体字段,无哈希表开销 - 验证方式:用
sys.getsizeof(obj)对比,或用pympler.asizeof.asizeof(obj)查更准的总内存 - 注意:
__slots__不影响类对象本身大小,也不压缩属性值(字符串、列表等仍独立存在)
真正容易被忽略的是兼容性代价——比如用 dataclasses 或 pydantic 时,默认机制依赖 __dict__,硬加 __slots__ 往往要配合 unsafe_hash=True 或重写 __init__,得不偿失。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











