第三个选项与前两个选项完全相同。第三个示例创建一个列表,每个列表对应print(i)的返回值,正好是None,因此不是一个非常有趣的列表。在
前两个在语义上是相似的。这里有一个小的技术上的区别;如果my_iter不是迭代器(即有一个__next__()方法),那么while循环就不起作用;例如,如果它是list。for循环适用于除迭代器之外的所有iterables(有一个__iter__()方法)。在
因此,正确的版本是:my_iter = iter(my_iterable)
try:
while True:
i = next(my_iter)
print(i)
except StopIteration:
pass
现在,除了可读性原因之外,事实上是一个您应该选择for循环的技术原因;对于在紧凑的内部循环中执行的字节码数量,您要付出一定的代价(无论如何,在CPython中)。让我们比较一下:
^{pr2}$
内环中调用的7字节码vs:In [55]: def whileloop(my_iterable):
....: my_iter = iter(my_iterable)
....: try:
....: while True:
....: i = next(my_iter)
....: print(i)
....: except StopIteration:
....: pass
....:
In [56]: dis.dis(whileloop)
2 0 LOAD_GLOBAL 0 (iter)
3 LOAD_FAST 0 (my_iterable)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 STORE_FAST 1 (my_iter)
3 12 SETUP_EXCEPT 32 (to 47)
4 15 SETUP_LOOP 25 (to 43)
5 >> 18 LOAD_GLOBAL 1 (next)
21 LOAD_FAST 1 (my_iter)
24 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
27 STORE_FAST 2 (i)
6 30 LOAD_GLOBAL 2 (print)
33 LOAD_FAST 2 (i)
36 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
39 POP_TOP
40 JUMP_ABSOLUTE 18
>> 43 POP_BLOCK
44 JUMP_FORWARD 18 (to 65)
7 >> 47 DUP_TOP
48 LOAD_GLOBAL 3 (StopIteration)
51 COMPARE_OP 10 (exception match)
54 POP_JUMP_IF_FALSE 64
57 POP_TOP
58 POP_TOP
59 POP_TOP
8 60 POP_EXCEPT
61 JUMP_FORWARD 1 (to 65)
>> 64 END_FINALLY
>> 65 LOAD_CONST 0 (None)
68 RETURN_VALUE
内环中有9个字节码。在
不过,我们实际上可以做得更好。在In [58]: from collections import deque
In [59]: def deqloop(my_iter):
....: deque(map(print, my_iter), 0)
....:
In [61]: dis.dis(deqloop)
2 0 LOAD_GLOBAL 0 (deque)
3 LOAD_GLOBAL 1 (map)
6 LOAD_GLOBAL 2 (print)
9 LOAD_FAST 0 (my_iter)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 LOAD_CONST 1 (0)
18 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
21 POP_TOP
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
所有的事情都发生在C中,collections.deque,map和{}都是内置函数。(对于cpython)所以在本例中,没有为循环执行字节码。只有当迭代步骤是一个c函数时,这才是一个有用的优化(例如print)。否则,python函数调用的开销大于JUMP_ABSOLUTE开销。在