__slots__能省内存,因它用固定偏移的C结构体替代默认的__dict__哈希表(省约240字节/实例),并移除__weakref__(除非显式声明);仅对当前类生效,子类需单独定义。

能减,但只在大量实例且属性固定时才值得用;盲目加 __slots__ 可能破坏继承、序列化或动态赋值逻辑。
为什么 __slots__ 能省内存?
默认情况下,Python 实例通过 __dict__ 存储属性,这是一个哈希表,开销大(约 240 字节起步);而 __slots__ 让解释器改用固定偏移的 C 结构体存储,去掉 __dict__ 和 __weakref__(除非显式声明),单个实例可节省上百字节。
常见错误现象:AttributeError: 'MyClass' object has no attribute 'xxx' —— 忘记把新属性名写进 __slots__ 元组里。
- 仅对**当前类**生效,子类不会自动继承(除非子类也定义
__slots__) - 不能和
__dict__共存:一旦定义__slots__,实例就不再有__dict__(除非显式加入'__dict__') - 动态添加属性会失败:
obj.new_attr = 1→ 报错,除非'__dict__'在 slots 中
怎么正确定义 __slots__?
必须是类变量,值为字符串元组或列表,列出所有允许的实例属性名。注意逗号别漏——__slots__ = ('x') 是字符串,不是元组;得写成 __slots__ = ('x',) 或 __slots__ = ['x']。
立即学习“Python免费学习笔记(深入)”;
使用场景:高频创建的轻量数据容器(如解析 CSV 行、ORM 模型实例、树节点)。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
class Point:
__slots__ = ('x', 'y') # ✅ 正确:两个属性
def __init__(self, x, y):
self.x = x
self.y = y
<h1>❌ 错误示例:</h1><h1><strong>slots</strong> = 'x' # → 等价于 ('x',)?不,是字符串,会报错</h1><h1><strong>slots</strong> = 'x', 'y' # → Python 会当成表达式,实际是 ('x', 'y'),但易读性差,不推荐和继承、@property、__weakref__ 怎么共存?
多重继承时,**只有所有父类都定义了 __slots__,且没有冲突,才能安全使用**;只要有一个父类没设 __slots__,子类的 __slots__ 就失效(因为父类仍会创建 __dict__)。
性能影响:访问速度略快(避免字典查找),但差别微乎其微;主要收益在内存,不在 CPU。
-
@property不受影响:它属于类,不占实例空间 - 需要弱引用?得显式加入
'__weakref__'到__slots__元组中 - 想保留动态赋值能力?加
'__dict__'—— 但那就基本抵消内存优势了
验证是否真省了内存?
别猜,用 sys.getsizeof() + __dict__ 对比看:
import sys
<p>class Regular:
def <strong>init</strong>(self, a, b):
self.a = a
self.b = b</p><p>class Slotted:
<strong>slots</strong> = ('a', 'b')
def <strong>init</strong>(self, a, b):
self.a = a
self.b = b</p><p>r = Regular(1, 2)
s = Slotted(1, 2)
print(sys.getsizeof(r)) # 通常 56 或更大(含 <strong>dict</strong>)
print(sys.getsizeof(s)) # 通常 32(无 <strong>dict</strong>)注意:sys.getsizeof() 不计算 __dict__ 里对象本身的大小,只算容器开销;真正压测得用 pympler.asizeof 或生成数万个实例看 RSS 占用。
最容易被忽略的一点:__slots__ 不压缩属性值本身(比如一个长字符串、大列表),它只省掉属性名到值的映射结构。如果值本身很大,加了 __slots__ 也几乎看不出变化。

















