python 3.11类实例化加速源于call和load_attr字节码的运行时特化,当__new__/__init__路径稳定、字段类型一致且使用__slots__时,内联缓存可跳过通用查找,大幅提升性能;但动态访问或字符串就地拼接(a += 'x')反而可能变慢。

Python 3.11 的类实例化性能提升不是来自语法或 API 变更,而是解释器在 CALL 和 LOAD_ATTR 字节码层面的特化(specialization)直接生效的结果——尤其当构造函数逻辑稳定、字段类型一致时,提升非常明显。
类实例化变快的核心原因:__new__ 和 __init__ 调用路径被特化
CPython 3.11 对高频调用指令做了运行时优化,而类实例化本质上就是连续触发:
-
CALL指令执行MyClass()→ 触发__new__和__init__ -
STORE_ATTR或LOAD_ATTR在初始化过程中频繁写入/读取字段(如self.name = name) - 若字段类型稳定(如
self.id: int、self.name: str),这些操作会被缓存为单态路径
这意味着:第二次及之后创建同类型实例时,跳过大部分对象布局查找和通用分派逻辑,直接走内联缓存路径。
哪些类定义能真正受益?
不是所有类都能拿到“接近 2×”的加速。以下条件越满足,提升越明显:
- 构造函数中不使用
**kwargs或动态setattr(),字段名和类型固定 - 避免在
__init__中做复杂计算或 I/O,让热点集中在属性赋值本身 - Pydantic v2 模型、dataclass(带
__slots__)是典型受益者——字段访问模式高度可预测 - 继承链短(单继承优于多层 MRO 查找),减少
LOAD_ATTR的通用查找开销
反例:getattr(obj, field_name) 或 self.__dict__[key] = value 会完全绕过特化机制,退化为 3.10 行为。
为什么有时反而更慢?字符串拼接是个坑
Python 3.11 移除了对 a += 'x' 这类操作的就地优化(in-place optimization),改由通用字符串拼接路径处理。如果你的 __init__ 里大量用 self.log += line 构建日志字段,实测可能比 3.10 慢一个数量级。
- 修复方式:改用
''.join([...])或f"{a}{b}" - 验证方法:用
dis.dis(MyClass.__init__)查看是否生成了BINARY_ADD(慢)而非INPLACE_ADD(3.10 快) - 该问题与特化无关,是字节码生成阶段的回归,容易被误判为“3.11 不稳定”
实际效果取决于进程生命周期和请求热度
特化状态存在内存中,且按线程隔离。这意味着:
- 短命进程(如 AWS Lambda、K8s liveness probe)每次启动都从零学习,首请求无加速
- Gunicorn prefork 模式下,子进程会继承父进程已积累的部分特化缓存,warmup 后才稳定
- Uvicorn 多 worker 场景中,每个 worker 独立积累,QPS 低时(
别只看 benchmark.py 的单次 timeit 结果——真实服务中,类实例化是否快,取决于它是不是那个被反复调用的“热路径”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











