为何在CPython中list(x for x in a)处理a=[0]比a=[]更快?
为何
list(x for x in [0])比list(x for x in [])更快? 最近我在Windows 10 Pro 2004 64位系统上,针对三个不同版本的CPython做了个有趣的性能测试——测试生成器转换成列表和元组的速度,结果发现了一个反直觉的现象:当输入列表是a=[0]时,list(x for x in a)的运行速度明显快于a=[]的情况;但换成tuple(x for x in a)时,结果完全相反。
List转换性能测试结果
我跑了5轮测试,取平均耗时整理成下表:
| CPython版本 | a=[]平均耗时 | a=[0]平均耗时 |
|---|---|---|
| 3.9.0 64-bit | ~456 ns | ~409 ns |
| 3.9.0 32-bit | ~547 ns | ~514 ns |
| 3.7.8 64-bit | ~511 ns | ~482 ns |
Tuple转换性能测试结果
同样跑了5轮测试,替换list为tuple后的结果:
| CPython版本 | a=[]平均耗时 | a=[0]平均耗时 |
|---|---|---|
| 3.9.0 64-bit | ~357 ns | ~405 ns |
| 3.9.0 32-bit | ~482 ns | ~541 ns |
| 3.7.8 64-bit | ~420 ns | ~468 ns |
基准测试代码
测试用的核心代码如下(测试tuple时只需把list替换成tuple):
from timeit import repeat setups = 'a = []', 'a = [0]' number = 10**6 print(*setups, sep=' ') for _ in range(5): for setup in setups: t = min(repeat('list(x for x in a)', setup, number=number)) / number print('%d ns' % (t * 1e9), end=' ') print()
为什么list的情况反直觉?
咱们先看列表的内存预分配行为,我用__sizeof__()做了验证:
>>> [].__sizeof__() 40 >>> list(x for x in []).__sizeof__() 40 >>> [0].__sizeof__() 48 >>> list(x for x in [0]).__sizeof__() 72
能明显看到:
- 处理空输入
[]时,生成的新列表和原空列表字节数一致,完全没有预分配额外空间; - 处理
[0]时,生成的新列表字节数远大于原列表(72 vs 48),说明CPython给它预分配了更多空间。
这背后的关键是CPython处理生成器转列表的底层逻辑:
- 当用生成器创建列表时,CPython会先调用生成器的
__length_hint__()方法,尝试获取预期的元素数量。对于从列表迭代的生成器,这个方法会直接返回原列表的长度。 - 如果原列表长度是0,
__length_hint__()返回0,list会直接创建一个空列表,没有任何预分配操作;但如果原列表长度是1,__length_hint__()返回1,list会触发它的“过度分配”策略——预分配比实际需要更多的空间,方便后续添加元素。
那为什么预分配反而更快?
- 空输入的分支在CPython底层是个单独处理路径,它需要额外检查生成器是否真的没有元素,涉及生成器的状态切换和边界判断;而非空输入的预分配路径是日常更常见的场景,优化得更充分。
- 预分配空间看似多了一步内存操作,但实际执行时,这部分逻辑是高度优化的C代码,反而比空输入的额外检查开销更小。
为什么tuple的结果完全相反?
元组和列表的底层实现有本质区别,这直接导致了性能差异:
- 元组是不可变对象,创建时不需要预分配额外空间,直接按元素数量分配刚好足够的内存。
- 对于空生成器的情况,CPython会直接返回一个预缓存的单例空元组(
()在Python里是全局唯一的),完全不需要新的内存分配;但处理包含一个元素的生成器时,必须创建新的元组对象,涉及内存分配和元素拷贝,这额外的开销直接拖慢了速度。 - 另外,迭代空生成器的过程几乎瞬间结束,不需要执行任何元素添加逻辑,进一步减少了耗时。
总结一下
- List场景:非空输入触发的预分配逻辑,避开了空输入时的额外边界检查,且预分配路径的优化更充分,因此速度更快;
- Tuple场景:空输入直接复用预缓存的单例空元组,无需内存分配,而非空输入必须创建新元组,因此空输入速度更快。
内容的提问来源于stack exchange,提问作者Kelly Bundy
相关产品推荐
相关产品推荐

