为什么打破而不是引发例外更快? - python

在检查了几个简单的测试之后,似乎从循环中中断以结束生成器可能比引发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异常。而且,这不是中途停止发电机的标准方法。

这是有关发电机的文档中有关如何正确停止它们的两个声明:

  • PEP 479 -- Change StopIteration handling inside generators:
  • ...该提案还消除了有关如何终止
    生成器:正确的方法是return,而不是raise StopIteration

  • PEP 255 -- Simple Generators
  • 问:为什么根本允许"return"?为什么不强迫终止拼写
    "raise StopIteration"

    A. StopIteration的机制是底层细节,就像
    Python 2.1中IndexError的机制:实现需要
    在幕后做了明确定义的事情,Python公开了
    这些机制适合高级用户。那不是为了
    但是,强迫每个人都在该级别上工作。 "return"表示“我是
    完成”,并且易于解释和使用。
    请注意,"return"并不总是等同于"raise StopIteration" 在try / except构造中,要么(请参见“规范:返回”
    部分)。

    因此正确的方法是使用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运算符>>打印到文件 - python

    我有以下Python代码编写项目的依赖文件。它可以在Python 2.x上正常工作,但是在使用Python 3进行测试时会报告错误。depend = None if not nmake: depend = open(".depend", "a") dependmak = open(".depend.mak&#…

    Python:检查是否存在维基百科文章 - python

    我试图弄清楚如何检查Wikipedia文章是否存在。例如,https://en.wikipedia.org/wiki/Food 存在,但是https://en.wikipedia.org/wiki/Fod 不会,页面只是说:“维基百科没有此名称的文章。”谢谢! 参考方案 >>> import urllib >>> prin…

    Python uuid4,如何限制唯一字符的长度 - python

    在Python中,我正在使用uuid4()方法创建唯一的字符集。但是我找不到将其限制为10或8个字符的方法。有什么办法吗?uuid4()ffc69c1b-9d87-4c19-8dac-c09ca857e3fc谢谢。 参考方案 尝试:x = uuid4() str(x)[:8] 输出:"ffc69c1b" Is there a way to…

    Python:对于长时间运行的进程,通过还是休眠? - python

    我正在编写一个队列处理应用程序,该应用程序使用线程等待和响应要发送到该应用程序的队列消息。对于应用程序的主要部分,只需要保持活动状态即可。对于像这样的代码示例:而True: 通过要么而True: time.sleep(1)哪一个对系统的影响最小?除了保持python应用运行外,什么都不做的首选方式是什么? 参考方案 我可以想象time.sleep()会减少系…

    Python:无符号32位按位算术 - python

    试图回答另一篇有关其解决方案涉及IP地址和网络掩码的文章时,我陷入了普通的按位算法。在Python中,是否存在一种标准的方式来进行按位AND,OR,XOR,NOT运算,假设输入是“32位”(可能是负数)整数或long,并且结果必须是[[ 0,2 ** 32]?换句话说,我需要一个与无符号长整数之间的C按位运算有效的Python对应物。编辑:具体问题是这样的:…