python`for i in iter` vs`on True; 我=下一个(iter)`

Tho*_*ner 3 python iteration

根据我的理解,这两种方法都适用于生成器中的每个项目:

  • 让我们i成为运营商的目标
  • my_iter我们的发电机
  • 让可驯服的do_something_with回报None

而Loop + StopIteratioon

try:
    while True:
        i = next(my_iter)
        do_something_with(i)
except StopIteration:
    pass
Run Code Online (Sandbox Code Playgroud)

对于循环/列表理解

for i in my_iter:
    do_something_with(i)
Run Code Online (Sandbox Code Playgroud)

[do_something_with(i) for i in my_iter]
Run Code Online (Sandbox Code Playgroud)

次要编辑:print(i)do_something_with(i)@kojiro建议替换,以便用解释器机制消除用例的歧义.


据我所知,这些都是迭代生成器的适用方法,有没有理由偏爱另一个?

现在for循环看起来比我优越.由于:较少的线条/杂乱和一般的可读性,加上单个缩进.

我真的只看到while方法是有利的,如果你想在特定异常上轻松打破循环.

Sin*_*ion 5

第三个选择是明确一样的第2位.第三个例子创建了一个列表,每个列表都有一个返回值print(i),它恰好是None,所以不是一个非常有趣的列表.

前两个在语义上相似.存在轻微的技术差异; 如所示,while循环不起作用my_iter,实际上是迭代器(即,有一个__next__()方法); 例如,如果是的话list.__iter__()除了迭代器之外,for循环适用于所有迭代(有一个方法).

因此,正确的版本是:

my_iter = iter(my_iterable)
try:
    while True:
        i = next(my_iter)
        print(i)
except StopIteration:
    pass
Run Code Online (Sandbox Code Playgroud)

现在,除了可读性原因之外,实际上一个技术原因你应该更喜欢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
Run Code Online (Sandbox Code Playgroud)

内循环vs中调用的7个字节码:

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
Run Code Online (Sandbox Code Playgroud)

内循环中的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
Run Code Online (Sandbox Code Playgroud)

一切都发生在C, collections.deque,map并且print都内建命令.(对于cpython)所以在这种情况下,没有执行循环的字节码.当迭代步骤是ac函数时,这只是一个有用的优化(就像这样print.否则,python函数调用的JUMP_ABSOLUTE开销大于开销.