Python 如何用 __slots__ 优化对象数量

10次阅读

__slots__ 通过禁用 __dict__ 并用固定结构存储属性,将每个实例内存从约240字节降至仅指针大小(如16字节),显著降低大量对象的总体内存占用

Python 如何用 __slots__ 优化对象数量

__slots__ 优化对象数量,核心是减少单个实例的内存占用,从而在创建大量对象时显著降低整体内存消耗。它不提升单次操作速度,但能让成千上万个实例更轻量、更紧凑。

为什么 __slots__ 能节省内存

默认情况下,python 对象通过 __dict__ 存储实例属性,这是一个动态字典,灵活但开销大(约 240 字节起步)。启用 __slots__ 后,Python 不再为每个实例创建 __dict__,而是将属性名预先声明为固定字段,底层用紧凑的 C 结构体存储——每个属性只占一个指针大小(通常 8 字节),且无哈希表管理成本。

  • 没有 __dict____weakref__(除非显式加入)
  • 属性访问仍为 O(1),且略快于字典查找
  • 类定义时即锁定属性名,运行时无法新增属性(如 obj.x = 1 会报错)

怎么正确使用 __slots__

在类定义中添加 __slots__ 类变量,值为字符串元组,列出所有允许的实例属性名:

class Point:     __slots__ = ('x', 'y') 
def __init__(self, x, y):     self.x = x     self.y = y

注意几点:

立即学习Python免费学习笔记(深入)”;

  • 父类用了 __slots__,子类也必须声明,否则子类会重新启用 __dict__,失去优化效果
  • 若需支持弱引用,显式把 '__weakref__' 加入 __slots__
  • 不能直接赋值给 __slots__(比如在 __init__ 中),它必须是类级常量
  • 类属性、方法、类变量不受影响,照常工作

什么时候该用 __slots__

适合高频创建、生命周期短、结构固定的轻量对象场景:

  • 数据容器类:如坐标点、RGB 值、csv 行解析结果
  • ORM 模型中的实体(尤其批量查询返回数千条记录时)
  • 游戏或仿真中成千上万个粒子、节点、状态对象

不适合需要动态增删属性、频繁 monkey patch、或依赖 __dict__ 的框架(如某些序列化库、调试工具)。

验证内存节省效果

可以用 sys.getsizeof() 粗略对比(注意:它不包含所引用对象的内存,仅实例本身):

from sys import getsizeof 

class RegularPoint: def init(self, x, y): self.x = x self.y = y

class SlottedPoint: slots = ('x', 'y') def init(self, x, y): self.x = x self.y = y

p1 = RegularPoint(1, 2) p2 = SlottedPoint(1, 2)

print(getsizeof(p1)) # 通常 32–48 字节(含 dict) print(getsizeof(p2)) # 通常 16–32 字节(仅两个指针 + 对象头)

创建 10 万个实例时,内存差可能达数 MB —— 在内存敏感服务中很可观。

text=ZqhQzanResources