slots 主要解决对象内存占用过大和属性动态滥用问题,通过禁用 dict 实现内存优化与属性名校验。

Python 的 __slots__ 主要解决对象内存占用过大和属性动态滥用的问题。它不是用来“加速访问”或“强制封装”的银弹,而是一个明确的契约:告诉解释器“这个类的实例只会有这些固定属性”,从而跳过默认的 __dict__ 字典开销。
减少每个实例的内存占用
普通 Python 对象默认为每个实例分配一个 __dict__(字典),用于存储任意动态属性。这个字典本身就有几百字节开销。当创建成千上万个轻量对象(比如解析大量日志、建模几何点、数据库行记录)时,内存会迅速膨胀。
启用 __slots__ 后,实例不再有 __dict__,属性值直接存放在预分配的固定内存偏移上,就像 C 结构体一样紧凑。实测中,单个实例内存可减少 40%–60%,尤其在小对象上效果显著。
- 不使用
__slots__:每个实例额外携带约 240–300 字节的__dict__开销(取决于 Python 版本和平台) - 使用
__slots__ = ('x', 'y', 'label'):属性以类似元组的紧凑结构存储,无哈希表查找开销
阻止意外的属性赋值
__slots__ 让类变成“封闭式接口”——只有声明过的属性名才能被设置。这能提前暴露拼写错误或误用,避免因打错属性名导致静默失败:
立即学习“Python免费学习笔记(深入)”;
-
obj.x = 1✅('x'在__slots__中) -
obj.x_coord = 1❌ 报AttributeError(未声明)
这种限制不是为了“封装”,而是提升代码健壮性,特别适合配置类、数据容器、DTO 等边界清晰的场景。
不适用于所有场景:注意限制
__slots__ 是有代价的,用前需确认是否符合需求:
- 子类也会继承
__slots__,若子类没定义自己的__slots__,则会重新创建__dict__,反而更混乱 - 无法动态添加属性(如
obj.new_field = 42)、不能用__dict__反射操作、不能被某些依赖字典的工具(如pprint、部分序列化库)直接处理 - 带默认值的
__slots__需配合dataclass或__init__手动初始化,它本身不提供默认值机制
典型适用场景
当你在写以下类型的类时,__slots__ 很可能值得考虑:
- 高频创建/销毁的小型数据载体(例如:
Point(x, y)、RGB(r, g, b)、Token(type, value, line)) - 需要大量实例驻留内存的服务端模型(如游戏实体、实时行情快照)
- 明确 API 边界的配置类或消息结构体,不允许随意扩展字段
如果类需要灵活扩展、支持动态属性、或本身就是基类/抽象类,那就别硬加 __slots__ —— 清晰比省几十字节更重要。










