能省,但只在特定场景下显著——对象数量过万、属性固定、不依赖__dict__时,单实例省16–40字节,百万级对象可降内存40%–70%;其原理是禁用__dict__字典(约240字节开销),改用紧凑数组存储属性,实现类似C结构体的偏移寻址。

能省,但只在特定场景下显著——对象数量过万、属性固定、不依赖__dict__时,单实例省 16–40 字节,百万级对象可降内存 40%–70%。
为什么__slots__能省内存
Python 默认给每个实例配一个 __dict__ 字典,哪怕只存一个 int,这个字典本身在 64 位 CPython 中就占约 240 字节(含哈希表头、空槽等“基础税”)。属性越多,字典预分配空间越大,还带内存碎片。
启用 __slots__ = ('x', 'y') 后:
- 实例彻底不生成
__dict__ - 属性值直接按顺序存进预分配的紧凑数组,每个引用仅占 8 字节(64 位系统)
- 访问变成类似 C 结构体的偏移寻址,跳过哈希计算和字典查找
实测:10 万个 Point 实例,普通类约 24 MB,加 __slots__ 后降到约 14 MB。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
__slots__ 的正确写法与高频报错
语法错一点就崩,不是运行时报错,而是解释器直接拒绝加载类。
-
__slots__ = 'x'❌ —— 字符串会被当迭代器拆成('x',),但行为未定义,多数情况直接SyntaxError或TypeError -
__slots__ = ('x',)✅ —— 单属性必须带逗号,元组才成立 -
__slots__ = ['x', 'y']✅ —— 列表也行,但元组更轻量 -
p.z = 1→AttributeError: 'Point' object has no attribute 'z'—— 漏声明就炸,不是静默忽略
子类继承时__slots__失效的典型场景
父类加了 __slots__,子类没加 → 子类实例仍会生成 __dict__,父类优化全白费。
- 子类必须显式声明自己的
__slots__,哪怕为空:__slots__ = () - 若需扩展属性,得手动合并:
__slots__ = ('new_attr',) + Parent.__slots__ - 多重继承时,所有父类都需有
__slots__,且不能有同名冲突,否则报TypeError
没加 __weakref__ 到 __slots__ 里?weakref.ref(obj) 直接失败。
哪些地方千万别硬上__slots__
它不是通用优化开关,强行加反而引入兼容性问题。
- 用了 Django Model、Flask Form、dataclass(没设
slots=True)—— 这些框架内部重度依赖__dict__ - 需要运行时动态赋值:
obj.debug_flag = True或vars(obj).update(...)会立即中断 - 用
json.dumps(obj)序列化?默认失败,因为没__dict__;得自己写default=回调或改用asdict() - 调试阶段频繁 monkey patch 或打桩——
__slots__会让临时加字段变成阻塞性错误
真正值得加的地方很窄:粒子系统、传感器采样点、网络协议包解析器、ORM 的只读 DTO——这些对象结构死、数量大、生命周期短、不参与框架魔改。

















