Python列表推导会转换为纯C吗?

2 投票
1 回答
1474 浏览
提问于 2025-04-18 11:32

我听说过很多次,Python 的列表推导式比嵌套的 forif 更好,原因是它们会被转换成纯 C 代码并编译。不过,我找不到任何文档来支持这个说法;这是真的吗?

举个例子,下面的代码在我的机器上确实提高了 1/3 的性能:

import time

start = time.time()
a = []
for i in range(0, 100000000):
  a.append(i)

end = time.time()

print("Time it took: " + str((end - start)))

start = time.time()
b = [i for i in range(0, 100000000)]
end = time.time()

print("Time it took: " + str((end - start)))

CPython 的结果:

Time it took: 12.077988863
Time it took: 8.65817594528

PyPy 的结果:

Time it took: 4.9356508255
Time it took: 0.686870098114

1 个回答

2

这跟具体的实现有关,但在CPython中,它并不是编译成C代码,而是编译成一种叫做“字节码”的东西。

我们可以用dis模块来查看这个字节码,它的作用是将字节码拆解开来。

>>> import dis
>>> def foo():
...     return [i//2 for i in range(20)]
... 
>>> dis.dis(foo)
  2           0 BUILD_LIST               0
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (20)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                16 (to 32)
             16 STORE_FAST               0 (i)
             19 LOAD_FAST                0 (i)
             22 LOAD_CONST               2 (2)
             25 BINARY_FLOOR_DIVIDE 
             26 LIST_APPEND              2
             29 JUMP_ABSOLUTE           13
        >>   32 RETURN_VALUE        

在其他实现中,它可能会被编译成C代码。我对那些其他实现不太熟悉,所以就不多说了。

关于你提到的:

列表推导比嵌套的for循环要好,如果……

在某些情况下,使用for循环和条件会更合适。最好的方法是选择你觉得最容易理解的方式,如果需要提高性能再去优化代码。有时候,你其实并不需要列表推导或生成器表达式创建的列表或生成器,这种情况下,使用带有if条件的for循环通常会更快。

猜测:

不过,在你给出的例子中,你是想要创建一个列表。通过循环向列表添加元素是最常见的做法,但正如你从运行时间中看到的,列表推导会更快。它更快的原因是,Python的设计者知道列表推导是用来填充列表的,因此有机会进行优化。而在for循环中,优化就比较困难,因为你需要处理更复杂的语句。

我想你在PyPy中看到的巨大提升,可能是因为某种优化,专门针对这一部分,或者简单地对你的迭代器调用了list

撰写回答