我相信 Python 两种形式(大致[1])是等效的:
# a convoluted way to generate the strings for the integers from 0 to 99
for x in range(10):
for y in range(10):
str(x*10+y)
和
[str(x*10+y) for x in range(10) for y in range(10)]
根据我的经验,确实如此。但我从来没有检查过。让我们去做吧:
>>> # The calls to `str` were not recorded for a strange reason,
>>> # so instead I create a dummy function that I will supply to the profiled code
>>> def foo(val): pass
>>> # I bump the value to 10000 so that it takes a few seconds to run,
>>> # so there is something to profile
>>> cProfile.runctx("for x in range(10000):\n\tfor y in range(10000):\n\t\tfoo(x*10000+y)",
globals={"foo": foo}, locals={})
100000003 function calls in 17.188 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
100000000 3.668 0.000 3.668 0.000 <input>:1(foo)
1 13.520 13.520 17.188 17.188 <string>:1(<module>)
1 0.000 0.000 17.188 17.188 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
>>> cProfile.runctx("[foo(x*10000+y) for x in range(10000) for y in range(10000)]",
globals={"foo": foo}, locals={})
100000004 function calls in 14.998 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
100000000 3.530 0.000 3.530 0.000 <input>:1(foo)
1 11.321 11.321 14.851 14.851 <string>:1(<listcomp>)
1 0.147 0.147 14.998 14.998 <string>:1(<module>)
1 0.000 0.000 14.998 14.998 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
foo 和 ncalls 都恰好是 100000000 (= 10000*10000)。
它与specification for comprehension lists "displays" 匹配:
理解由一个表达式组成,后跟至少一个 for 子句和零个或多个 for or if 子句。在这种情况下,新容器的元素是通过将每个 for 或 if 子句视为一个块,从左到右嵌套,并在每次最里面时计算表达式以生成一个元素来生成的元素已到达区块。
换句话说:理解的效果是一样的[1] 就好像for 已经以相同的顺序嵌套,并且内部循环的每次迭代都添加了一个新值.但是正如你所看到的,它还是有点快。
[1]:来自the same spec as before,“理解在单独的隐式嵌套范围内执行。这确保分配给目标列表的名称不会“泄漏”到封闭范围内”。换句话说,这意味着您无法在理解之外访问您的x 和y。
旁注:有很多 Python 初学者教程,但实际上它们很少实现复杂的行为。为此,您通常会寻找实际的“生产”代码(通常在 GitHub 或 PIP 上)。