• Python基础:14生成器


             yield表达式只用于定义生成器函数,且只能存在于函数的定义体中。只要一个函数内部使用了yield表达式,则该函数就成为生成器函数。

             当调用生成器函数时,它返回一个称为生成器的迭代器。然后该生成器控制生成器函数的执行。当调用生成器的其中一个方法时,执行开始。此时,执行会行进到第一个yield表达式,在那里执行被挂起并返回一个值给生成器的调用者。挂起的意思是保存所有的局部状态,包括当前局部变量的绑定、指令的指针和内部的计算栈。当通过调用生成器的一个方法来恢复执行时,函数可以准确地继续执行,就好像yield表达式只是一个外部的调用。恢复执行后yield表达式的值取决于恢复执行的方法。

            所有这些使得生成器函数与协程非常类似;它们可以yield多次,它们有多个入口点且它们的执行可以挂起。唯一的区别是生成器函数不可以控制yield之后执行应该从何处继续;控制始终被转让给生成器的调用者。

            生成器函数,要么没有return语句,要么带有空的return语句,否则,会引起语法错误。

     

            调用生成器,当到达一个真正的返回或者函数没有更多的值返回时,一个StopIteration 异常就会抛出。简单例子如下:

    def  simpleGen():
            yield  1
            yield  '2 -->punch!'
            return
            yield  4
     
    >>>myG  =  simpleGen()
    >>>myG.next()
    1
    >>>myG.next()
    '2 -->punch!'
    >>>myG.next()
    Traceback (mostrecent call last):
    File"", line 1, in ?
    StopIteration

     

            生成器迭代器的方法。它们可用于控制生成器函数的执行。注意当生成器已经在执行时,调用下面的任何一个生成器方法都将引发ValueError异常。

     1:generator.next()

            开始生成器函数的执行或者在上一次执行的yield表达式之后恢复执行。然后执行继续行进到下一个yield表达式,在那里生成器被再次挂起并返回值给next()的调用者。当生成器函数使用next()方法恢复执行时,当前的yield表达式的值始终是None。如果生成器退出时没有yield另外一个值,则引发一个StopIteration异常。比如下面的代码:

    def  gen():
            while  True:
                    print 'before yield'
                    res  =  yield random.randint(1, 100)
                    print  'res is ',  res
     
    >>> ag = gen()
    >>> ag
    <generator  object  gen at  0x0000000002645168>
     
    >>> ag.next()
    before  yield
    12
    >>> ag.next()
    res is None
    before  yield
    14

    2:generator.send(value)

            开始生成器函数的执行或者在上一次执行的yield表达式之后恢复执行,并“发送”一个值value到生成器中,该value参数成为当前yield表达式的结果。send()方法返回生成器yield的下一个值,如果生成器退出时没有yield另外一个值则引发StopIteration。 当调用send()用于开始生成器的执行时,它必须以None作为参数进行调用,因为没有接受该值的yield表达式。

    >>> ag2  =  gen()
    >>> ag2
    <generator  object  gen at  0x00000000026451F8>
    >>> ag2.send(None)
    before  yield
    28
    >>> ag2.send(1)
    res  is  1
    before  yield
    61
    >>> ag2.send('hehe')
    res  is  hehe
    before  yield
    21
    >>> ag2.next()
    res  is  None
    before  yield
    22
    >>> ag3 = gen()
    >>> ag3.send(1)
    Traceback (most recent call last):
      File"<stdin>", line 1, in <module>
    TypeError: can't send non-None value to ajust-started generator

    3:generator.throw(type[, value[, traceback]])

            在生成器暂停的地方引发一个type类型的异常,并返回生成器函数yield的下一个值。如果生成器在退出时没有yield一个值,则引发StopIteration异常。如果生成器函数没有捕获传递进来的异常或者引发一个不同的异常,那么该异常将传播到调用者。例子如下:

    def  gen():
           while True:
                  print 'before  yield'
                  try:
                         res = yield  random.randint(1,100)
                  except Exception ,e:
                         print 'recv except: ',  e
                  print 'res is ',  res
     
    >>> ag  =  gen()
    >>> ag.next()
    before  yield
    68
    >>> ag.next()
    res  is  None
    before  yield
    48
    >>> ag.throw(TypeError,  1)
    recv  except: 1
    res  is  None
    before  yield
    37
     
    >>> ag.throw(KeyboardInterrupt, 1)
    Traceback (most recent call last):
      File"<stdin>", line 1, in <module>
      File"test.py", line 7, in gen
        res =yield random.randint(1,100)
    KeyboardInterrupt: 1
    >>> ag.next()
    Traceback (most recent call last):
      File"<stdin>", line 1, in <module>
    StopIteration

    4:generator.close()

            在生成器函数暂停的地方引发一个GeneratorExit。如果生成器函数此后引发StopIteration(正常退出或者由于已经正在关闭),或者没有捕获GeneratorExit异常,close会返回到调用者。否则,如果生成器yield一个值,则引发一个RuntimeError。如果生成器引发其它任何异常,它会被传播到调用者。如果生成器已经由于异常退出或正常退出,close()不会做任何事情。

    def  gen():
           while True:
                  print 'before  yield'
                  try:
                         res =  yield  random.randint(1,100)
                  except Exception ,e:
                         print 'recv except: ',  e
                  print 'res is ',  res
     
    >>> ag2  =  gen()
    >>> ag2.close()
    >>> ag2.send(2)
    Traceback (most recent call last):
      File"<stdin>", line 1, in <module>
    StopIteration
    >>> ag2.next()
    Traceback (most recent call last):
      File"<stdin>", line 1, in <module>
    StopIteration
     
    def  gen():
           while True:
                  print 'before yield'
                  try:
                         res =  yield random.randint(1,100)
                  except Exception ,e:
                         print 'recv except: ', e
                  except GeneratorExit, e:
                         print 'recv exit: ', e
                  print 'res is ',  res
     
    >>> ag  =  gen()
    >>> ag.next()
    before  yield
    4
    >>> ag.next()
    res  is  None
    before  yield
    16
    >>>ag.close()
    recv  exit:
    res  is  None
    before yield
    Traceback(most recent call last):
      File "<stdin>", line 1, in<module>
    RuntimeError:generator ignored GeneratorExit

            可以在PEP 的255 和342 中,以及给读者介绍python2.2 中新特性的linux 期刊文章中阅读到更多关于生成器的资料:http://www.linuxjournal.com/article/5597

     

    参考:

    http://python.usyiyi.cn/python_278/reference/expressions.html#yieldexpr

    https://docs.python.org/2/reference/expressions.html#yieldexpr

     

    http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html

    http://pyzh.readthedocs.org/en/latest/the-python-yield-keyword-explained.html


  • 相关阅读:
    nvm安装node的问题
    前端必读:浏览器内部工作原理
    读书笔记:《高性能网站建设指南》
    学习前端我读过的书
    Canvas绘制圆形进度条
    gitlab升级方法
    设置root远程连接ubuntu上mysql
    SpringMVC的@ResponseBody返回JSON,中文乱码问题的解决.
    JSTL 格式化输出 Calendar
    在Maven的配置文件中,自定义私有仓库地址和设置下载的jar包的保存位置
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247201.html
Copyright © 2020-2023  润新知