__slots__能省下几百字节/实例,是因为禁用默认的__dict__字典(约240字节)和__weakref__(8字节),改用共享字段映射+连续内存块存储属性值,砍掉哈希表、字符串键及指针管理等冗余开销。

__slots__ 为什么能省下几百字节/实例?
因为默认情况下,每个 Python 实例都自带一个 __dict__ 字典——哪怕你只存 x 和 y 两个 int,这个字典本身就要占约 240 字节(64 位 CPython 下的典型值),外加对象头 56 字节。而 __slots__ 直接禁用 __dict__,改用紧凑的固定偏移数组存储属性值,相当于把“哈希表+字符串键+指针管理”整套开销砍掉,只留纯数据。
不加 __slots__ 的实例内存结构长什么样?
一个空的自定义类实例(比如 class A: pass)在 CPython 中至少占 56 字节对象头;一旦你赋值 self.x = 1,解释器就立刻分配一个完整哈希表作为 __dict__,初始大小通常是 8 个桶(即使只存 1 个键),实际占用常达 240–360 字节。更麻烦的是:__weakref__ 也会默认存在,再加 8 字节。这些都不是你的业务数据,全是“基础设施税”。
加了 __slots__ 后内存怎么变紧凑?
__slots__ 让解释器提前知道所有字段名,于是:
- 所有实例共享一份字段名到内存偏移的映射(存在类对象里,只一份)
- 每个实例只分配刚好够存声明字段的连续内存块(例如
__slots__ = ['x', 'y']→ 两个PyObject*指针,16 字节) - 不再生成
__dict__和默认__weakref__(除非你显式写进__slots__)
Point(x, y) 实例,普通类占约 28MB,加 __slots__ 后压到 4.3MB —— 不是比例夸张,是底层结构真的换了。
为什么父类没 __slots__,子类加了也几乎不省?
因为继承链上只要有一个父类没定义 __slots__,它就会把 __dict__ 传给子类实例(CPython 规则)。子类即使写了 __slots__,也只管自己新增字段,无法覆盖父类已带的 __dict__。结果就是:内存还是被那个字典吃掉大头。要真省,必须从最顶层基类开始统一加,且中间不能断档。
真正省内存的关键不在语法有多短,而在你是否愿意为每个类明确划清属性边界——一旦接受这个约束,__slots__ 就不是技巧,而是对象建模的自然延伸。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











