Python 3.12 推导式内联仅对一次性迭代消费生效,如sum([x*x for x in data]);赋值复用、显式构造器、嵌套推导式均不触发。

PEP 709 推导式内联只对单次消费生效
Python 3.12 的推导式性能跃升不是靠“更快地建列表”,而是直接跳过建列表。但这个优化有严格触发条件:sum([x*x for x in data]) 能内联,lst = [x*x for x in data]; sum(lst); max(lst) 就完全不触发。
常见误用场景:
- 把推导式赋值给变量再复用——立刻退化为 3.11 行为
- 传给
sorted()、list()、tuple()等显式构造器——它们本意就是造容器,不内联 - 嵌套推导式如
[[i+j for j in range(10)] for i in range(10)]——外层仍是列表推导,不满足“一次性迭代消费”语义
小对象内存布局压缩降低 GC 压力
短字符串(≤40 字节)、小元组(≤3 元素)、小整数等高频对象在 3.12 中结构体更紧凑:str 从 49 bytes → 41 bytes,tuple 从 40 bytes → 32 bytes。这不是省内存的噱头,而是让 CPU 缓存一次加载更多有效数据,间接加速循环和属性访问。
但压缩只作用于新创建对象:
立即学习“Python免费学习笔记(深入)”;
-
copy.copy()或deepcopy()复制的对象仍用旧布局 - NumPy 的
.item()返回值走的是 C API 分配路径,不享受压缩 - 频繁新建短生命周期字典(如每行都
{'status': 'ok', 'code': 200})会抵消收益,应改用预分配list+ 索引映射
字节码专门化减少循环开销
旧版本中 for item in data: 每次迭代都要查 data.__iter__ 和迭代器方法;3.12 在字节码层面做了专门化(specialization),对常见可迭代类型(list、tuple、range)生成专用指令路径,跳过通用查找逻辑。
实测影响明显:
- 纯计数循环
for _ in range(10_000_000): pass快约 15% - 文件读取
open("big.txt").readlines()快 30%,但for line in f:提升微乎其微——它本来就是流式、低开销的 - 该优化对自定义类的
__iter__无效,只针对内置类型
GC 自动收缩策略改变运行时行为
3.12 的垃圾回收器不再依赖固定计数器(比如“每分配 700 个对象就检查一次”),而是结合堆使用率、存活对象衰减趋势和访问局部性熵,在空闲期主动归还内存池。这对长期运行服务(Flask/Gunicorn 进程)效果显著:24 小时后 RSS 内存比 3.11 低 35%。
你不需要改代码,但要注意:
-
gc.collect()手动调用变少——不是失效了,而是自动触发更准、更轻量 - 大量使用
__del__方法的类,可能暴露此前被静默吞掉的异常(现在由sys.unraisablehook捕获) - 如果脚本本身只跑几秒就退出,这个优化几乎不可见
list(...) 或反复赋值,就等于主动绕过所有加速路径。



















