Python __slots__ 内存优化实战与副作用分析

Cora
Cora
发布时间:2026-10-13| 2人浏览过
原创

本文通过《Fluent Python》案例验证Python中__slots__的内存节省效果,显示50万个实例可大幅降低内存占用。同时深入剖析其副作用:子类需重定义__slots__、限制动态属性添加及弱引用支持问题。结论指出,对于实例数不足万级的场景,__slots__并非必要,需根据业务规模权衡使用。

前言

相信许多资深Python开发者都读过那篇极具吸引力的文章《Saving 9 GB of RAM with Python's slots》,其中作者利用__slots__将内存占用从25.5GB降至16.2GB。在当时看来,这种简单方式实现了30%的内存缩减,效果令人惊叹。由于作者未披露具体业务场景和代码细节,我们将基于《Fluent Python》中的示例进行验证,以确认其实际效果是否如描述般显著。

from __future__ import print_function
import resource
class A(object):
 def __init__(self):
 self.a = 'string'
 self.b = 10
 self.c = True
class B(object):
 __slots__ = ['a', 'b', 'c']
 def __init__(self):
 self.a = 'string'
 self.b = 10
 self.c = True
def test(cls):
 mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
 l = []
 for i in range(500000):
 l.append(cls())
 mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
 del l
 print('Class: {}:\n'.format(getattr(cls, '__name__')))
 print('Initial RAM usage: {:14,}'.format(mem_init))
 print(' Final RAM usage: {:14,}'.format(mem_final))
 print('-' * 20)
if __name__ == '__main__':
 import sys
 test(globals()[sys.argv[1].upper()])

我们分别运行以下两个类的测试代码:

❯ python mem_test.py a
Class: A:
Initial RAM usage: 4,890,624
 Final RAM usage: 200,454,144
--------------------
❯ python mem_test.py b
Class: B:
Initial RAM usage: 4,919,296
 Final RAM usage: 60,235,776

两种方法初始化后的初始内存略有差异,但该差异相对于总内存量极小,可忽略不计。由此得出的结论是:

使用__slots__可使内存使用量减少约3.5倍!# 该数值通过公式 (200 - 4) / ((60 - 4) * 1.0) 计算得出

那么,使用__slots__是否非常有必要?事实上,创建500000个实例的场景在现实中较为罕见,是否使用应完全取决于具体业务需求,切忌以偏概全。因为(此处需重点注意)使用__slots__会引入以下副作用:

  1. 每个继承的子类都必须重新定义一遍__slots__。
  2. 实例只能包含在__slots__中定义的属性,这会影响编程的灵活性。例如,若因某种原因想给instance动态设置一个新属性(如instance.a = 1),但由于a未在__slots__中定义,程序将直接报错。此时你必须不断修改__slots__或采用其他迂回方法来解决。
  3. 实例无法支持弱引用(weakref)目标,除非显式将__weakref__加入__slots__中。

第三点可能较难理解,下面通过一个示例进行说明:

In [2]: %pycat ref_example.py
from weakref import ref
class A(object):
 __slots__ = ['b']
 def __init__(self):
 self.b = 1
class B(object):
 __slots__ = ['b', '__weakref__']
 def __init__(self):
 self.b = 1
In [3]: from ref_example import *
In [4]: a = A()
In [5]: r = ref(a)
---------------------------------------------------------------------------
TypeError     Traceback (most recent call last)
<ipython-input-6-75a6d689c8b3> in <module>()
----> 1 r = ref(a)
TypeError: cannot create weak reference to 'A' object
In [6]: b = B()
In [7]: r = ref(b)
In [8]: r
Out[8]: <weakref at 0x109199578; to 'B' at 0x10919f890>

因此,对于实例数量不超过万级别的类,使用__slots__通常不太值得。

PS:《Fluent Python》中的观点更为激进,认为实例数小于百万级别的场景均不值得使用__slots__。

总结

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对本站的支持。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。