python generator

近期看了tornado的源码,gen模块使用yield实现了coroutine(协程),一个函数中一旦使用

了yield语句,那么这个函数可以说就是个generator function了。

example 1:

<span style="font-size:18px;">  1 #coding: utf-8
  2 def gen1():
  3     print 'hi, this is in the gen1 generator'
  4     yield 1
  5 if __name__ == '__main__':
  6     g = gen1()
  7     print 'type(g)', type(g)</span></span>

在终端中执行结果如下:

type(g) <type 'generator'>

从输出可以看出,gen1不再是一个函数而是一个generator了,从输出可以看到,第六行

gen1()的调用,并没有真正的执行函数体,要是执行了的话,第三行应该可以输出内

容!这是generator function与普通函数的一个区别之一:普通函数在第一次调用就开始

执行函数体,而generator function的第一次调用只是生成了一个generator function

对象,并不执行函数体。

example 2:

<span style="font-size:18px;">  1 #coding: utf-8
  2 def gen2():
  3     print 'hi, before yield 1'
  4     yield 1
  5     print 'hi, after yield  1'
  6 
  7 if __name__ == '__main__':
  8     g = gen2()
  9     ret = g.next()
 10     print 'ret :', ret</span></span>
在终端中输出如下:

hi, before yield 1
ret : 1

从输出可以看出,第5行明显没有执行,不然会有输出的。这是generator function的一个

特性:当一个generator function在执行到包含有yield关键字的语句时,函数的执行会

被挂起(例子中是gen2函数),从而回到调用方(if __name__ == '__main__'下面的语句),

yield后面的表达式计算的结果作为返回值返回给调用方(这里赋值给了ret变量)。如果再

次调用这个generator函数调用,函数会从上次被挂起的地方开始执行。在例子中应该是

第4行。

example 3:

<span style="font-size:18px;">  1 #coding: utf-8
  2 def gen3():
  3     print 'hi, before yield 1'
  4     yield 1
  5     print 'hi, after yield  1'
  6 
  7 if __name__ == '__main__':
  8     g = gen3()
  9     ret = g.next()
 10     print 'ret :', ret
 11     g.next()</span></span>
在终端中输出如下:

hi, before yield 1
ret : 1
hi, after yield  1
Traceback (most recent call last):
  File "generator.py", line 11, in <module>
    g.next()
StopIteration

输出中可以看出,第11行的调用输出了执行了gen3函数的第5行,然后抛出了一个异常。

这也说明了generator function的另一个特性:当整个generator function函数正常(在执

行期间没有抛出未捕获的异常)执行完毕时,会抛出一个StopIteration异常。这点和iterator

是一样的。

example 4:

<span style="font-size:18px;">  1 #coding: utf-8
  2 def gen4():
  3     print 'hi, before yield 1'
  4     yield 1
  5     print 'hi, after yield  1'
  6     return 2
  7 if __name__ == '__main__':
  8     g = gen4()</span></span>
在执行的时候输出如下:

  File "generator.py", line 6
    return 2
SyntaxError: 'return' with argument inside generator

也就是说有语法错误。这个异常也说明了generator function的一个特性:generator function

中return语句后面不能跟任何的表达式语句将代码中第六行的return 2 换成return就正确了。

example 5:

<span style="font-size:18px;">  1 #coding: utf-8
  2 def gen5():
  3     n = yield 2
  4     print 'n = ', n
  5 
  6 def send_data(n):
  7     g = gen5()
  8     ret = g.next()
  9     print 'ret = ', ret
 10     g.send(n)
 11 if __name__ == '__main__':
 12     send_data(3)</span></span>
终端中输出如下:

ret =  2
n =  3
Traceback (most recent call last):
  File "generator.py", line 12, in <module>
    send_data(3)
  File "generator.py", line 10, in send_data
    g.send(n)
StopIteration

从输出中可以看出,ret获取了yield的值,而n的值则是第10行中send的参数值。generator

有send方法,send的值作为yield的返回值,如果没有send方法的话,yield返回None,

一个值得注意的输出是,程序在第10行抛出了异常,这是send方法引起的,generatorsend

方法会将调用方挂起,并且会唤醒被挂起的generator function,简单一点来说send的功能

相当于一次next调用,并且送去了一个值,这个值是yield语句的返回值。利用send唤醒被挂

起的generator function是tornado实现协程的核心。generator 能够调用send方法的一个前提是

这个generator function已经开始,也就是说这个generator function至少目前为止是处于挂起状态的。

example 6:

<span style="font-size:18px;">  1 #coding: utf-8
  2 def gen6():
  3     n = yield 2
  4     print 'n = ', n
  5 
  6 def throw():
  7     g = gen6()
  8     ret = g.next()
  9     print "ret = ", ret
 10     g.throw(IndexError, IndexError('test for generator throw method'), None)
 11 if __name__ == '__main__':
 12     throw()</span></span>
终端中输出如下:

ret =  2
Traceback (most recent call last):
  File "generator.py", line 12, in <module>
    throw()
  File "generator.py", line 10, in throw
    g.throw(IndexError, IndexError('test for generator throw method'), None)
  File "generator.py", line 3, in gen6
    n = yield 2
IndexError: test for generator throw method

从输出的异常信息中可以看到,第10行使挂起的generator function产生了一次,generator 有throw

函数,使用该函数可以向generator function抛出一个异常throw的三个参数分别是type, type-value, 

traceback。和sys.exc_info()函数返回的三个值是一致的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值