You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在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处理生成器转列表的底层逻辑:

  1. 当用生成器创建列表时,CPython会先调用生成器的__length_hint__()方法,尝试获取预期的元素数量。对于从列表迭代的生成器,这个方法会直接返回原列表的长度。
  2. 如果原列表长度是0,__length_hint__()返回0,list会直接创建一个空列表,没有任何预分配操作;但如果原列表长度是1,__length_hint__()返回1,list会触发它的“过度分配”策略——预分配比实际需要更多的空间,方便后续添加元素。

那为什么预分配反而更快?

  • 空输入的分支在CPython底层是个单独处理路径,它需要额外检查生成器是否真的没有元素,涉及生成器的状态切换和边界判断;而非空输入的预分配路径是日常更常见的场景,优化得更充分。
  • 预分配空间看似多了一步内存操作,但实际执行时,这部分逻辑是高度优化的C代码,反而比空输入的额外检查开销更小。

为什么tuple的结果完全相反?

元组和列表的底层实现有本质区别,这直接导致了性能差异:

  1. 元组是不可变对象,创建时不需要预分配额外空间,直接按元素数量分配刚好足够的内存。
  2. 对于空生成器的情况,CPython会直接返回一个预缓存的单例空元组(()在Python里是全局唯一的),完全不需要新的内存分配;但处理包含一个元素的生成器时,必须创建新的元组对象,涉及内存分配和元素拷贝,这额外的开销直接拖慢了速度。
  3. 另外,迭代空生成器的过程几乎瞬间结束,不需要执行任何元素添加逻辑,进一步减少了耗时。

总结一下

  • List场景:非空输入触发的预分配逻辑,避开了空输入时的额外边界检查,且预分配路径的优化更充分,因此速度更快;
  • Tuple场景:空输入直接复用预缓存的单例空元组,无需内存分配,而非空输入必须创建新元组,因此空输入速度更快。

内容的提问来源于stack exchange,提问作者Kelly Bundy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 16:02:45