在判断了一些简单的测试之后,似乎从循环中断到结束生成器可能比引发StopIteration异常更快.如果标准且公认的停止发电机的方法使用异常,为什么会出现这种情况.source

In [1]: def f():
   ....:     for i in range(1024):
   ....:         yield None
   ....:         break
   ....:     

In [2]: def g():
   ....:     for i in range(1024):
   ....:         yield None
   ....:         raise StopIteration
   ....:     

In [3]: %timeit for i in f(): pass
1000000 loops, best of 3: 1.22 µs per loop

In [4]: %timeit for i in g(): pass
100000 loops, best of 3: 5.9 µs per loop

In [5]: %timeit for i in f(): pass
1000000 loops, best of 3: 1.22 µs per loop

In [6]: %timeit for i in g(): pass
100000 loops, best of 3: 5.82 µs per loop

推荐答案

如果标准且公认的停止发电机的方法使用异常,为什么会出现这种情况.

只有当发电机不再生产任何产品时,才会引发异常StopIteration.而且,这不是中途停止发电机的标准方法.

以下是有关发电机的文档中关于如何正确停止发电机的两条声明:

  1. PEP 479 -- Change StopIteration handling inside generators:

... 该提案还澄清了关于如何终止合同的困惑

  1. PEP 255 -- Simple Generators

问:为什么允许"return"人?为什么不强制拼写终止

答:StopIteration的机制是低级细节,很像

所以正确的方法是使用return语句,而不是使用breakraise StopIteration.


似乎从一个循环到break结束一个生成器可能比引发StopIteration异常更快.

事实上,这是因为当提出例外时,有更多的工作要做.您可以使用dis模块查看字节码:

In [37]: dis.dis(f)
  2           0 SETUP_LOOP              26 (to 29)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (1024)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                12 (to 28)
             16 STORE_FAST               0 (i)

  3          19 LOAD_CONST               0 (None)
             22 YIELD_VALUE         
             23 POP_TOP             

  4          24 BREAK_LOOP          
             25 JUMP_ABSOLUTE           13
        >>   28 POP_BLOCK           
        >>   29 LOAD_CONST               0 (None)
             32 RETURN_VALUE        

In [38]: dis.dis(g)
  2           0 SETUP_LOOP              31 (to 34)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (1024)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                17 (to 33)
             16 STORE_FAST               0 (i)

  3          19 LOAD_CONST               0 (None)
             22 YIELD_VALUE         
             23 POP_TOP             

  4          24 LOAD_GLOBAL              2 (StopIteration)
             27 RAISE_VARARGS            1
             30 JUMP_ABSOLUTE           13
        >>   33 POP_BLOCK           
        >>   34 LOAD_CONST               0 (None)
             37 RETURN_VALUE

您可以看到,几乎所有内容都是一样的,但要引发异常,它必须执行一些额外的指令:

24 LOAD_GLOBAL              2 (StopIteration)
27 RAISE_VARARGS            1

Python-3.x相关问答推荐

如何从枚举中获取某个值?

从PYTHON中获取单行和多行的Rguar表达式

合并两个数据帧并对某些总和进行求和

继承自 Counter 与 dict 的类实例的 Deepcopy

通过在不重新索引的情况下采用最高概率的百分比,有效地转换 0/1 列表中的概率列表

python2和python3中的列表生成器

Python BeautifulSoup:在 Select 语句中排除其他标签

机器学习实验笔记本的工作区 url

如何从 Python 3.5 降级到 Python 3.4

日志(log)模块不适用于 Python3

判断对 python 3 支持的要求

如何判断一个字符串是否包含有效的 Python 代码

为什么我在 Python 中收到错误消息无法导入名称 NoneType?

pandas 中 df.reindex() 和 df.set_index() 方法的区别

是否有与 Laravel 4 等效的 python?

迭代dict值

所有 Python dunder 方法的列表 - 您需要实现哪些方法才能正确代理对象?

Python3 的超级和理解-> TypeError?

pdfminer python 3.5

十六进制字符串到 Python 3.2 中的带符号整数?