__slots__能降低内存占用,因为它禁用每个实例默认的__dict__字典(开销约240+字节),改用连续内存块存储预定义属性,类似c struct,单实例可节省数百字节,十万实例节省mb级内存。

为什么 __slots__ 能降低内存占用
Python 默认为每个实例动态创建一个 __dict__ 字典来存储属性,哪怕只存一两个字段,也要承担哈希表的固定开销(通常 240+ 字节)。启用 __slots__ 后,实例不再生成 __dict__,属性被分配在连续内存块中,类似 C struct —— 每个实例能省下几百字节,尤其在创建数万以上对象时效果明显。
但注意:它不是万能压缩器。如果类本身方法多、继承深,或你仍需动态设属性,__slots__ 反而会带来限制和麻烦。
怎么正确定义 __slots__
在类定义中直接声明 __slots__ 为字符串元组,列出所有**允许的实例属性名**:
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
常见错误和要点:
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
- 必须是元组(哪怕只有一个属性),写成列表或字符串会静默失效
- 父类用了
__slots__,子类也必须显式定义,否则子类实例仍会生成__dict__ - 不支持给实例加未声明的属性:
p = Point(1, 2); p.z = 3会抛AttributeError - 若需保留
__dict__(例如调试或临时扩展),可在__slots__中加入'__dict__',但就失去大部分内存优势
哪些场景下 __slots__ 不起作用或要小心
以下情况会让 __slots__ 失效或引发意外:
- 类定义了
__getstate__、__setstate__或继承自有这些方法的类(如某些 ORM 基类) - 使用了多重继承,且任一父类没定义
__slots__—— Python 会退回到传统__dict__模式 - 试图通过
setattr(obj, 'attr', val)动态赋值未声明属性,直接报错;但getattr(obj, '__dict__', {})会返回空或不存在 - 用
dataclasses.dataclass时,默认不兼容__slots__,需显式传参@dataclass(slots=True)(Python 3.10+)
验证内存节省效果的实际方法
别靠猜,用 sys.getsizeof() 和 __dict__ 存在性对比:
import sys
<p>class RegularPoint:
def <strong>init</strong>(self, x, y):
self.x = x
self.y = y</p><p>class SlottedPoint:
<strong>slots</strong> = ('x', 'y')
def <strong>init</strong>(self, x, y):
self.x = x
self.y = y</p><p>r = RegularPoint(1, 2)
s = SlottedPoint(1, 2)</p><p>print(sys.getsizeof(r)) # 通常是 32 or 48
print(sys.getsizeof(s)) # 通常是 16 or 24
print(hasattr(r, '<strong>dict</strong>')) # True
print(hasattr(s, '<strong>dict</strong>')) # False
</p>
真正关键的是批量实例的总内存差异。单个省十几字节,十万实例就差出 MB 级别。但如果你只创建几十个对象,或者类里存着大数组、大字符串,__slots__ 的收益几乎可以忽略。
它最该用在“大量轻量数据载体”上,比如几何点、事件消息、解析后的 JSON 对象 —— 而不是业务逻辑复杂的主模型类。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










