列表理解在 Python 中到底是如何工作的?

Sid*_*Sid 3 python list-comprehension

我正在浏览 Python 3.X 的文档,我对列表理解的执行速度及其具体工作原理有疑问。

让我们看下面的例子:

清单 1

...
L = range(0,10)
L = [x ** 2 for x in L]
...
Run Code Online (Sandbox Code Playgroud)

现在据我所知,这会返回一个新列表,相当于写下

清单 2

...
res = []
for x in L:
  res.append(x ** 2)
...
Run Code Online (Sandbox Code Playgroud)

如果我是正确的话,主要区别在于执行速度。清单 1 应该在解释器内以 C 语言速度执行,而清单 2 则不然。

但清单 2 是列表理解在内部执行的操作(不确定),那么为什么清单 1 在解释器内以 C 速度执行,而清单 2 则不是?两者在处理之前都转换为字节码,还是我遗漏了一些东西?

Jam*_*s K 5

查看生成的实际字节码。我已将这两个代码片段放入名为 f1 和 f2 的函数中。

理解是这样做的:

  3          15 LOAD_CONST               3 (<code object <listcomp> at 0x7fbf6c1b59c0, file "<stdin>", line 3>)
             18 LOAD_CONST               4 ('f1.<locals>.<listcomp>')
             21 MAKE_FUNCTION            0
             24 LOAD_FAST                0 (L)
             27 GET_ITER
             28 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             31 STORE_FAST               0 (L)
Run Code Online (Sandbox Code Playgroud)

请注意,字节码中没有循环。循环发生在 C 中。

现在 for 循环执行以下操作:

  4          21 SETUP_LOOP              31 (to 55)
             24 LOAD_FAST                0 (L)
             27 GET_ITER
        >>   28 FOR_ITER                23 (to 54)
             31 STORE_FAST               2 (x)
             34 LOAD_FAST                1 (res)
             37 LOAD_ATTR                1 (append)
             40 LOAD_FAST                2 (x)
             43 LOAD_CONST               3 (2)
             46 BINARY_POWER
             47 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             50 POP_TOP
             51 JUMP_ABSOLUTE           28
        >>   54 POP_BLOCK
Run Code Online (Sandbox Code Playgroud)

与理解相反,循环显然在字节码中。所以在python中就出现了循环。

字节码不同,第一个应该更快。