当百万级对象吞噬内存时,__slots__如同Python性能优化的暗黑艺术,用空间换时间的博弈颠覆传统对象模型。
内存吞噬者:动态字典的原罪
普通Python类实例通过__dict__字典动态存储属性:
class User:
pass
u = User()
u.name = "Alice" # 动态写入__dict__
每个实例需额外存储字典数据结构(约240字节基础开销),百万实例即浪费240MB内存。
__slots__的魔法阵
声明固定属性列表,替换动态字典:
class SlotUser:
__slots__ = ('name', 'age') # 预定义属性白名单
su = SlotUser()
su.name = "Bob" # 直接写入固定内存槽
su.email = "x@x" # 触发AttributeError!
- 内存优化:消除
__dict__和__weakref__(若未显式声明)开销 - 访问加速:数组索引访问 vs 字典哈希查找
性能实测:数据不说谎
import sys
class DictClass: pass
class SlotClass: __slots__ = ('x',)
dict_objs = [DictClass() for _ in range(100000)]
slot_objs = [SlotClass() for _ in range(100000)]
print(sys.getsizeof(dict_objs)) # ≈22.4MB
print(sys.getsizeof(slot_objs)) # ≈12.5MB (节省44%)
继承链中的暗雷
class Parent:
__slots__ = ('a',)
class Child(Parent):
__slots__ = ('b',) # 合并父类slots:实际为('a','b')
class GrandChild(Child):
__slots__ = Parent.__slots__ + Child.__slots__ # 显式合并最佳实践
- 子类未声明
__slots__时继承父类但获得__dict__ - 多继承需手动合并所有父类
__slots__
适用场景:性能与灵活的抉择
|
场景 |
推荐使用 |
不推荐使用 |
|
高频创建小对象 |
✅ | |
|
需动态添加属性 |
❌ (丧失灵活性) | |
|
内存敏感型应用 |
✅ | |
|
复杂继承结构 |
⚠️ 谨慎 |
警示:__slots__不是银弹。在Django等ORM框架中滥用会破坏动态查询,而在需要weakref或pickle的场景需显式声明__weakref__。下个问题:当__slots__遇见元类编程时,会碰撞出怎样的火花?
7万+

被折叠的 条评论
为什么被折叠?



