Python __slots__ 内存优化Python 类默认使用 __dict__ 存储实例属性带来灵活性但消耗额外内存。__slots__ 通过固定属性列表大幅减少内存占用。1. __slots__ 基本声明------------------------声明 __slots__ 后实例不再有 __dict__属性存储在固定数组中。class Point:使用 __slots__ 的类——每个实例节省约 40-60 字节__slots__ (x, y) # 只允许这两个属性def __init__(self, x: float, y: float):self.x xself.y yp Point(1.0, 2.0)print(p.x, p.y) # 1.0 2.0——正常访问# p.z 3.0 # AttributeError! 没有 __slots__ 声明 z# 验证没有 __dict__# print(p.__dict__) # AttributeError: Point object has no attribute __dict__2. 内存节省测量--------------------通过 sys.getsizeof 对比内存占用差异。import sysclass RegularPoint:普通类——有 __dict__def __init__(self, x: float, y: float):self.x xself.y yclass SlotPoint:使用 __slots__ 的类__slots__ (x, y)def __init__(self, x: float, y: float):self.x xself.y y# 创建大量对象测试内存差异regular_pts [RegularPoint(i, i) for i in range(10000)]slot_pts [SlotPoint(i, i) for i in range(10000)]# getsizeof 只返回单个对象大小不含内部引用的对象reg_size sys.getsizeof(regular_pts[0])slot_size sys.getsizeof(slot_pts[0])diff reg_size - slot_sizeprint(f普通对象大小: {reg_size} 字节) # 约 56 字节print(f__slots__ 对象大小: {slot_size} 字节) # 约 40 字节print(f每个对象节省: {diff} 字节) # 约 16 字节print(f10000 个对象共节省: {diff * 10000} 字节)3. __slots__ 与继承-----------------------子类需要重新声明 __slots__否则会继承父类的 __dict__。class Base:基类有 __slots____slots__ (id,)def __init__(self, id_: int):self.id id_class Derived(Base):子类必须也声明 __slots__否则会有 __dict____slots__ (name,) # 子类独有的槽def __init__(self, id_: int, name: str):super().__init__(id_)self.name nameclass BadDerived(Base):子类没有 __slots__——会有 __dict__失去优化效果def __init__(self, id_: int, extra: str):super().__init__(id_)self.extra extra # 可以动态添加属性bd BadDerived(1, test)print(bd.extra) # test——可以动态添加print(hasattr(bd, __dict__)) # True——有 __dict__浪费内存4. 在 __slots__ 中加入 __dict__------------------------------------如需保留动态添加属性的能力可将 __dict__ 加入 __slots__。class FlexibleSlot:既有 __slots__ 节省部分内存又保留动态添加的灵活性__slots__ (x, y, __dict__) # 明确保留 __dict__def __init__(self, x: float, y: float):self.x xself.y yf FlexibleSlot(1.0, 2.0)f.z 3.0 # 可以动态添加——因为有 __dict__print(f.z) # 3.0# 注意这种情况下内存节省效果减弱因为仍有 __dict__5. 约束没有 __weakref__-------------------------------默认情况下__slots__ 类不支持弱引用__weakref__ 也被优化掉。import weakrefclass SlotClass:__slots__ (x,)def __init__(self):self.x 10obj SlotClass()# ref weakref.ref(obj) # TypeError! 没有 __weakref__# 解决办法将 __weakref__ 加入 __slots__class WeakSlotClass:__slots__ (x, __weakref__) # 允许弱引用def __init__(self):self.x 10obj2 WeakSlotClass()ref weakref.ref(obj2) # 正常工作print(ref()) is obj2 # True6. __slots__ 在 dataclass 中--------------------------------Python 3.10 的 dataclass 支持 slotsTrue 参数。from dataclasses import dataclassdataclass(slotsTrue) # Python 3.10自动生成 __slots__class DataPoint:自动使用 __slots__ 的 dataclassx: floaty: floatlabel: str dp DataPoint(1.0, 2.0, A)# dp.extra 3 # AttributeError——没有 __dict__7. 何时使用 __slots__-------------------------适用场景- 创建大量实例百万级的对象如粒子系统、游戏实体- 数据载体类Value Object / DTO- 需要严格控制属性名称的场景不适用场景- 需要动态添加属性的场景除非加入 __dict__- 类层次复杂继承关系混乱时- 需要大量使用 weakref除非加入 __weakref__import tracemalloc# 内存对比演示tracemalloc.start()class DataContainer:普通数据容器def __init__(self, a, b, c):self.a, self.b, self.c a, b, cclass SlottedDataContainer:__slots__ 优化版__slots__ (a, b, c)def __init__(self, a, b, c):self.a, self.b, self.c a, b, c# 创建大量实例对比regular [DataContainer(i, i1, i2) for i in range(50000)]slotted [SlottedDataContainer(i, i1, i2) for i in range(50000)]# 注意当实例数量巨大时百万级__slots__ 节省的内存非常可观print(__slots__ 在大量实例场景下能显著降低内存使用)总结__slots__ 通过固定属性列表消除 __dict__以牺牲灵活性为代价换取内存效率和属性访问速度。在需要创建大量实例的高性能场景中非常有用。使用时注意继承、weakref 和动态属性等约束。