gpt4 book ai didi

python `for i in iter` 与 `while True; i = next(iter)`

转载 作者:太空宇宙 更新时间:2023-11-03 12:47:28 24 4
gpt4 key购买 nike

据我了解,这两种方法都适用于对生成器中的每个项目进行操作:

  • i成为我们的运营商目标
  • my_iter成为我们的发电机
  • 让调用do_something_with返回 None

While 循环 + StopIteration

try:
while True:
i = next(my_iter)
do_something_with(i)
except StopIteration:
pass

For循环/列表理解

for i in my_iter:
do_something_with(i)

[do_something_with(i) for i in my_iter]

次要编辑:print(i)替换为 do_something_with(i)正如@kojiro 所建议的那样,用解释器机制来消除用例的歧义。


据我所知,这些都是遍历生成器的适用方法,是否有任何理由更喜欢其中一种?

现在 for 循环看起来比我好。由于:更少的行/困惑和一般的可读性,加上单个缩进。

如果您想在特定异常情况下轻松打破循环,我真的只认为 while 方法有优势。

最佳答案

第三个选项显然与前两个选项相同。第三个示例创建了一个列表,每个列表对应于 print(i) 的返回值,它恰好是 None,因此不是一个非常有趣的列表。

前两个在语义上相似。存在细微的技术差异;如前所述,如果 my_iter 不是迭代器(即具有 __next__() 方法),则 while 循环不起作用;例如,如果它是一个 list。除了迭代器之外,for 循环适用于所有可迭代对象(具有 __iter__() 方法)。

因此正确的版本是:

my_iter = iter(my_iterable)
try:
while True:
i = next(my_iter)
print(i)
except StopIteration:
pass

现在,除了可读性原因之外,事实上还有一个技术原因,您应该更喜欢 for 循环;在紧密的内部循环中执行的字节码数量(无论如何,在 CPython 中)是有代价的。让我们比较一下:

In [1]: def forloop(my_iter):
...: for i in my_iter:
...: print(i)
...:

In [57]: dis.dis(forloop)
2 0 SETUP_LOOP 24 (to 27)
3 LOAD_FAST 0 (my_iter)
6 GET_ITER
>> 7 FOR_ITER 16 (to 26)
10 STORE_FAST 1 (i)

3 13 LOAD_GLOBAL 0 (print)
16 LOAD_FAST 1 (i)
19 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 POP_TOP
23 JUMP_ABSOLUTE 7
>> 26 POP_BLOCK
>> 27 LOAD_CONST 0 (None)
30 RETURN_VALUE

在内部循环中调用的 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.dequemapprint 都是内置函数。 (对于 cpython)所以在这种情况下,没有为循环执行的字节码。这只是一个有用的优化,当迭代步骤是一个 c 函数时(如 print 的情况)。否则,python 函数调用的开销大于 JUMP_ABSOLUTE 开销.

关于 python `for i in iter` 与 `while True; i = next(iter)`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27760818/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com