• Python 生成器与它的 send,throw,close 方法(转帖以及记录)


    Python 生成器与它的 send,throw,close 方法

    转载请注明出处:https://blog.csdn.net/jpch89/article/details/87036970

    在生成器中,无论生成器是什么状态,都可以直接使用throw与close。

    生成器这一块,对于next,send网上的介绍比较多,但对于throw以及close很多书上写的比较少,可能用的比较少,好在网上有很多介绍。

    以下是流畅的Python对throw和close的介绍:

    generator.throw(exc_type[, exc_value[, traceback]])

    致使生成器在暂停的yield表达式处抛出指定的异常。如果生成器处理了抛出的异常,代码会向前执行到下一个yield表达式,而产出的值会调用generator.throw方法得到的返回值。如果生成器没有处理抛出的异常,异常会向上冒泡,传到调用方的上下文中。

    generator.close()

    致使生成器在暂停的yield表达式处抛出GeneratorExit异常。如果生成器没有处理这个异常,或者抛出了StopIteration异常(通常是指运行到结尾),调用方不会报错。如果收到GeneratorExit异常,生成器一定不能产出值,否则解释器会抛出RuntimeError异常。生成器抛出的其他异常会向上冒泡,传给调用方。

    next就是send(None)

    生成器第一次需要预激,到达第一个yield处,预激可以用next或send(None),预激将产出第一个值,并到达第一个yield处

    到达yield处可以send(object)了。

    In [319]: def demo(): 
         ...:     for i in range(5): 
         ...:         res = yield i 
         ...:         print(res) 
         ...:                                                                                                                              
    
    In [320]: d = demo()                                                                                                                   
    
    In [321]: type(d)                                                                                                                      
    Out[321]: generator
    
    In [322]: next(d)                                                                                                                      
    Out[322]: 0
    
    In [323]: d.send('ok')                                                                                                                 
    ok
    Out[323]: 1
    
    In [324]: d.send(None)                                                                                                                 
    None
    Out[324]: 2
    
    In [325]: next(d)                                                                                                                      
    None
    Out[325]: 3
    
    In [326]: next(d)                                                                                                                      
    None
    Out[326]: 4
    
    In [327]: next(d)                                                                                                                      
    None
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-327-9b2daf1403f5> in <module>
    ----> 1 next(d)
    
    StopIteration: 
    
    In [328]: next(d)                                                                                                                      
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-328-9b2daf1403f5> in <module>
    ----> 1 next(d)
    
    StopIteration: 
    

     简单的测试了next与send,接着测试throw.

    按照前面书中的说明,throw以后如果抓取到错误,执行except内的语句,然后寻找下一个yield,所以如果在最后一个yield处throw,就算抓取在生成器中抓取到错误也会上浮错误信息

    StopIteration。当throw进去一个错误,生成器内部没有处理,当外部调用生成器的时候捕获了上浮的错误,此时生成器已经关闭,如果再次使用next与send会包stopIteration。

    (这里我重点笔记一下throw(StopIteration),因为当throw这个的时候,报的错误是RuntimeError)

    In [1]: def xx(): 
       ...:     yield 1 
       ...:                                                                                                            
    
    In [2]: x = xx()                                                                                                   
    
    In [3]: x.throw(NameError)                                                                                         
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    <ipython-input-3-9c1a5a069c11> in <module>
    ----> 1 x.throw(NameError)
    
    <ipython-input-1-c25019d2c434> in xx()
    ----> 1 def xx():
          2     yield 1
          3 
    
    NameError: 
    
    In [4]: x = xx()                                                                                                   
    
    In [5]: next(x)                                                                                                    
    Out[5]: 1
    
    In [6]: x.throw(NameError)                                                                                         
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    <ipython-input-6-9c1a5a069c11> in <module>
    ----> 1 x.throw(NameError)
    
    <ipython-input-1-c25019d2c434> in xx()
          1 def xx():
    ----> 2     yield 1
          3 
    
    NameError: 
    
    In [7]:        
    

     上面这个是普通的没有去获取任何异常的情况下,可以发现,生成器没有预激的情况下,也可以throw错误,只不过上浮的错误显示,报错的方位不一样。

    没有预激的生成器在def处就发现了错误,预激的生成器在第一个yield处发生了错误。

    我测试了很多不同的错误,一般不管在预激还是没有预激的情况下,扔什么错误,在没有捕获的情况下,就上浮错误,但StopIterations是一个例外。

    In [33]: def xx(): 
        ...:     yield 1 
        ...:     yield 2 
        ...:                                                                                                           
    
    In [34]: x = xx()                                                                                                  
    
    In [35]: next(x)                                                                                                   
    Out[35]: 1
    
    
    
    In [37]: try: 
        ...:     x.throw(ValueError,'ValueError_my') 
        ...: except ValueError as e: 
        ...:     print(e) 
        ...:                                                                                                           
    ValueError_my
    
    In [38]: inspect.getgeneratorstate(x)                                                                              
    Out[38]: 'GEN_CLOSED'
    
    In [39]: next(x)                                                                                                   
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-39-92de4e9f6b1e> in <module>
    ----> 1 next(x)
    
    StopIteration: 
    

     上面是一个没有捕获错误,外部捕获了错误,但生成器已经关闭了。

    In [40]: def xx(): 
        ...:     try: 
        ...:         yield 1 
        ...:         yield 2 
        ...:     except TypeError: 
        ...:         print('info type error') 
        ...:          
        ...:                                                                                                           
    
    In [41]: x = xx()                                                                                                  
    
    In [42]: x.throw(TypeError)                                                                                        
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-42-c568e586b030> in <module>
    ----> 1 x.throw(TypeError)
    
    <ipython-input-40-97b8907fc7a9> in xx()
    ----> 1 def xx():
          2     try:
          3         yield 1
          4         yield 2
          5     except TypeError:
    
    TypeError: 
    
    In [43]: x = xx()                                                                                                  
    
    In [44]: next(x)                                                                                                   
    Out[44]: 1
    
    In [45]: x.throw(TypeError)                                                                                        
    info type error
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-45-c568e586b030> in <module>
    ----> 1 x.throw(TypeError)
    
    StopIteration: 
    
    In [46]: def xx(): 
        ...:     try: 
        ...:         yield 1 
        ...:         yield 2 
        ...:     except TypeError: 
        ...:         print('info type error') 
        ...:     yield 3 
        ...:      
        ...:          
        ...:                                                                                                           
    
    In [47]: x = xx()                                                                                                  
    
    In [48]: next(x)                                                                                                   
    Out[48]: 1
    
    In [49]: x.throw(TypeError)                                                                                        
    info type error
    Out[49]: 3
    
    In [50]: next(x)                                                                                                   
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-50-92de4e9f6b1e> in <module>
    ----> 1 next(x)
    
    StopIteration: 
    
    In [51]:                                                                                                           
    

     上面的例子测试了没有预激的情况下,throw错误,生成器内部完全不能捕获任何没有预激情况下的错误,而且该生成器也将关闭。

    在预激的情况下,可以捕获设置的错误,并且寻找下一个yield,如果没有下一个yield,上浮StopIteration

    In [54]: def xx(): 
        ...:     try: 
        ...:         yield 1 
        ...:         yield 2 
        ...:     except StopIteration: 
        ...:         print('info stop') 
        ...:     yield 3 
        ...:      
        ...:          
        ...:                                                                                                           
    
    In [55]: x = xx()                                                                                                  
    
    In [56]: x.throw(StopIteration)                                                                                    
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-54-ebd45e0bac35> in xx()
    ----> 1 def xx():
          2     try:
          3         yield 1
    
    StopIteration: 
    
    The above exception was the direct cause of the following exception:
    
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-56-c41944ac436e> in <module>
    ----> 1 x.throw(StopIteration)
    
    RuntimeError: generator raised StopIteration
    
    In [57]: x = xx()                                                                                                  
    
    In [58]: next(x)                                                                                                   
    Out[58]: 1
    
    In [59]: x.throw(StopIteration)                                                                                    
    info stop
    Out[59]: 3
    
    In [60]: x.throw(StopIteration)                                                                                    
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-54-ebd45e0bac35> in xx()
          6         print('info stop')
    ----> 7     yield 3
          8 
    
    StopIteration: 
    
    The above exception was the direct cause of the following exception:
    
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-60-c41944ac436e> in <module>
    ----> 1 x.throw(StopIteration)
    
    RuntimeError: generator raised StopIteration
    
    In [61]:                                                                                                           
    

     从上面的列子可以看出只要没有捕获StopItoration,就上浮RuntimeError,而且这个错误是就因为StopItoration引起的。

    但如果在生成器内部预设了捕获StopItoration,则还是跟不同的逻辑是一样的。

    我的理解为,应该为如果没有捕获StopItoration,直接用了什么方法调用生成了新的错误,上浮给调用者,避免与StopItoration错误重复。

    最后是close,按照书中的说法跟我自己的理解,就是在yield处抛出Generation,可以通过except捕获到错误,但捕获了以后,后面不能再有yield产出值,要不然包RuntimeError。

    就算不捕获也没关系,不会上浮任何的错误,只不过该协程已经关闭了。

    In [61]: def xx(): 
        ...:     try: 
        ...:         yield 1 
        ...:         yield 2 
        ...:     except GeneratorExit: 
        ...:         print('info stop') 
        ...:     yield 3 
        ...:      
        ...:      
        ...:          
        ...:                                                                                                           
    
    In [62]: x= xx()                                                                                                   
    
    In [63]: x.close()                                                                                                 
    
    In [64]: next(x)                                                                                                   
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-64-92de4e9f6b1e> in <module>
    ----> 1 next(x)
    
    StopIteration: 
    
    In [65]: x= xx()                                                                                                   
    
    In [66]: next(x)                                                                                                   
    Out[66]: 1
    
    In [67]: x.close()                                                                                                 
    info stop
    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-67-f6d031a59762> in <module>
    ----> 1 x.close()
    
    RuntimeError: generator ignored GeneratorExit


    In [68]: x= xx()                                                                                                   

    In [69]: next(x)                                                                                                   
    Out[69]: 1

    In [70]: x.throw(GeneratorExit)                                                                                    
    info stop
    Out[70]: 3

    最后,我自己总结一下thorw与close的笔记,两个函数都可以不需要预激的情况下面执行。

    但执行的时候,生成器内部不会捕获到该异常。

    预激了以后,throw所有的异常都能捕获,捕获到该异常后,向下执行寻找下一个yield,产出值,没有yield就上浮StopItoration

    close在预激了以后,能通过except捕获到该GeneratorExit异常,但except向下的代码不能出现yield产出值,要不然会抛出RuntimeError

    如果throw(StopItoration),如果没有捕获该错误,上浮的错误为RuntimeError

    一个生成器关闭了,还能继续使用close函数,且不会报错。

    最后,一个生成器内部如果发生错误,没有捕获,这个生成器就马上进行关闭。

  • 相关阅读:
    88. Merge Sorted Array
    87. Scramble String
    86. Partition List
    85. Maximal Rectangle
    84. Largest Rectangle in Histogram
    83. Remove Duplicates from Sorted List
    82. Remove Duplicates from Sorted List II
    81. Search in Rotated Sorted Array II
    80. Remove Duplicates from Sorted Array II
    计算几何——点线关系(叉积)poj2318
  • 原文地址:https://www.cnblogs.com/sidianok/p/12229822.html
Copyright © 2020-2023  润新知