zoukankan      html  css  js  c++  java
  • 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函数,且不会报错。

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

  • 相关阅读:
    gulp打包js/css时合并成一个文件时的顺序解决
    gulp错误GulpUglifyError: unable to minify JavaScript解决
    日志平台中心建议
    Spring Boot整合Quartz实现定时任务表配置
    阿里云Centos7使用yum安装MySQL5.6的正确姿势
    Servlet、Filter
    Android java.lang.IllegalArgumentException: Object returned from onCreateLoader must not be a non-static inn
    Android中CursorLoader的使用、原理及注意事项
    Android LoaderManager与CursorLoader用法
    Android 用SQLite 使用 CursorLoader 中的数据填充列表视图
  • 原文地址:https://www.cnblogs.com/sidianok/p/12229822.html
Copyright © 2011-2022 走看看