【发布时间】:2016-08-04 07:24:30
【问题描述】:
是否在循环的每次重复中调用 foo()?
for num in foo():
# Do something
如果这样效率低下,这段代码更好吗?
l = foo()
for num in l:
# Do something
【问题讨论】:
标签: python python-3.x for-loop
是否在循环的每次重复中调用 foo()?
for num in foo():
# Do something
如果这样效率低下,这段代码更好吗?
l = foo()
for num in l:
# Do something
【问题讨论】:
标签: python python-3.x for-loop
没有。在两者中,foo() 都只被调用一次。可以预期前者比后者稍快。此外,list 是内置函数/类型的名称,您不应将其用作变量名称。
您可以使用 Python 字节码反汇编器dis.dis 找出 CPython 生成的字节码:
>>> import dis
>>> dis.dis(compile('for num in foo():pass', '', 'exec'))
1 0 SETUP_LOOP 17 (to 20)
3 LOAD_NAME 0 (foo)
6 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
9 GET_ITER
>> 10 FOR_ITER 6 (to 19)
13 STORE_NAME 1 (num)
16 JUMP_ABSOLUTE 10
>> 19 POP_BLOCK
>> 20 LOAD_CONST 0 (None)
23 RETURN_VALUE
在上面的字节码中,循环体从10 FOR_ITER 开始,一直持续到19 POP_BLOCK。比较:
>>> dis.dis(compile('l = foo()\nfor num in list:pass', '', 'exec'))
1 0 LOAD_NAME 0 (foo)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 STORE_NAME 1 (l)
2 9 SETUP_LOOP 14 (to 26)
12 LOAD_NAME 1 (l)
15 GET_ITER
>> 16 FOR_ITER 6 (to 25)
19 STORE_NAME 2 (num)
22 JUMP_ABSOLUTE 16
>> 25 POP_BLOCK
>> 26 LOAD_CONST 0 (None)
29 RETURN_VALUE
这里循环体从位置 16 开始,一直持续到 25。循环体的字节码是相同的;唯一的区别是额外的操作码STORE_NAME 将foo() 的返回值存储到list 中,以及额外的LOAD_NAME 用于从list 中检索值。
【讨论】:
foo 在第一个示例中的每次迭代都被调用,那么后者会更有效。事实上,无论创建和访问变量需要多长时间,后者的效率都较低。