用__slots__能显著降低实例内存,因为其禁用__dict__字典而改用固定偏移的C结构体布局,避免哈希表开销(通常240字节以上),仅保留声明字段所需空间;但需确保类不继承带__dict__的父类且放弃动态属性能力。

用 __slots__ 能显著降低实例内存,但前提是类不继承自有 __dict__ 的父类、且你明确放弃动态属性能力。
为什么 __slots__ 能省内存?
默认情况下,Python 实例通过 __dict__(一个字典)存储所有属性,哪怕只存 1 个字段,也要承担字典的哈希表开销(通常至少 240 字节)。__slots__ 禁用 __dict__,改用固定偏移的 C 结构体布局,每个实例只保留声明字段所需空间(比如 2 个 int 就约 16 字节)。
常见错误现象:AttributeError: 'MyClass' object has no attribute '__dict__' —— 这不是 bug,是预期行为;一旦定义了 __slots__,就不能再给实例赋值未声明的属性。
- 必须在类定义顶层直接声明,不能在
__init__或运行时动态添加 - 如果父类没设
__slots__,子类加了也几乎不省内存(因为继承了父类的__dict__) - 想支持某些字段可选?用
None或默认值初始化,别靠动态增删
如何正确声明 __slots__?
它必须是字符串序列(tuple、list、set 都行),每个字符串对应一个允许的属性名。注意:不包含方法名、类变量、或以双下划线开头的特殊方法(如 __init__)。
class Point:
__slots__ = ('x', 'y') # ✅ 正确:只允许 x 和 y
<pre class="brush:php;toolbar:false;">def __init__(self, x, y):
self.x = x
self.y = y
错误示例:
self.z = 10 # AttributeError!z 不在 slots 中
self.dict # AttributeError!slots 关闭了 dict
- 若需同时支持属性和
__dict__(极少见),得显式把'__dict__'加进__slots__,但这会抵消大部分内存收益 - 继承时,子类
__slots__默认不继承父类的 slots;如需叠加,子类也得声明,并手动包含父类字段名 - 元类或抽象基类可能干扰 slots 行为,测试前先用
vars(instance)确认是否真没了__dict__
哪些场景下 __slots__ 效果最明显?
内存节省比例取决于「单实例原始数据大小」与「__dict__ 固定开销」的比值。字段越少、实例越多,收益越直观。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
典型高收益场景:
- 高频创建/销毁的轻量对象,如解析 JSON 后的 DTO、游戏中的粒子、网络包头结构
- 含大量数值字段但逻辑简单的类(如
Vector3、RGBA),避免字典哈希查找延迟 - 用
__slots__+__weakref__(需显式加入 slots)实现弱引用支持,否则弱引用无法绑定到无__dict__实例
反例:带复杂业务逻辑、需运行时 patch 属性、或频繁用 setattr/getattr 动态操作的类 —— 强行上 __slots__ 只会增加维护成本。
真正要注意的不是语法怎么写,而是确认整个继承链都“干净”:没有父类偷偷带 __dict__,没有第三方库的 mixin 暗中注入属性,也没有调试时习惯性敲 obj.debug_flag = True 这种操作。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










