生成器方法漫谈(generator function)
生成器方法(generator function)作为一个可选特性在Python2.2中首次出现,2.3版本中内置支持了此特性,yield成为了关键字,生成器在后续版本中得到增强(比如增加了异常处理等特性)。C#2.0中也引入类似特性(迭代器),这两者之间有不少相似之处。本文针对IronPython 2.0 beta3进行讨论。
任何包含yield表达式的函数即为生成器方法,同时yield也只在定义一个生成器方法时使用。生成器方法是一个特殊的方法,当你调用生成器方法时,返回的不是像普通函数一样的单一值,而是返回了一个迭代器(相当于C#中的System.Collections.IEnumerator接口)。yield表达式会返回一个值:val = (yield i) ,val的值即为表达式的值。但是这个值并不是i,这个值是由调用生成器的send(value)方法指定的。如果不调用此方法或者调用send(None)方法,则返回值为None。而迭代器本身的返回值则是由yield语句(注意yield表达式[val = (yield i)]和yield语句[yield i]的区别)指定的,当每次调用迭代器的next()/send()方法时,yield语句会立即返回一个值给调用方,同时会保存当前代码执行位置及现场状态,并暂停执行(此时yield表达式还未被执行,即val没被赋值)。当再次调用迭代器的方法时将从此位置(yield表达式)恢复执行直到再次遇到下一个yield表达式。
下面将根据生成器支持的操作方法具体介绍:
next()
>>> def generate_ints(N):
for i in range(N):
yield i

>>> gen=generate_ints(3)
>>> gen
<generator object at 0x000000000000002B>
>>> gen.next()
0
>>> gen.next()
1
>>> gen.next()
2
>>> gen.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration: 引发类型为“IronPython.Runtime.Exceptions.StopIterationException
”的异常。send(value)
>>> def counter (maximum):
i=0
while i < maximum:
val = (yield i)
#如果设置了yield表达式的值,则将改变计数器的值
if val is not None:
i=val
else:
i+=1

>>> it=counter(10)
>>> print it.next()
0
>>> print it.send(8)
8
>>> print it.next()
9
>>> print it.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration: 引发类型为“IronPython.Runtime.Exceptions.StopIterationException
”的异常。
>>>注意:首次调用时,不可以用send()方法去赋一个非None值,因为这个值没有yield表达式去接收,否则会引发一个TypeError异常:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generatorthrow( type[, value[, traceback]])
throw(type, value=None, traceback=None)用来在生成器内部引发一个异常。异常在生成器暂停执行处由yield表达式引发。我们知道当生成器缺少yield表达式而结束的时候会拋出一个StopIteration异常而结束,我们也可以用throw()来传入一个异常给生成器,从而控制生成器的执行。当在生成器内部没有对传入的异常进行捕获处理时,异常将返回给调用者。
>>> def throw():
i=0
while True:
i+=1
try:
yield i
except StopIteration, v:
print "Caught StopIteration"
#这里是为了示例在生成器里如何捕获throw()传进的异常,
#所以还把异常返回给调用方,结束生成器
raise v

>>> g=throw()
>>> g.next()
1
>>> g.next()
2
>>> g.throw(StopIteration)
Caught StopIteration
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration: 引发类型为“IronPython.Runtime.Exceptions.StopIterationException
”的异常。
>>>close()
有了上面的throw()方法的介绍后,现在理解close()就容易多了。此方法会在生成器暂停执行处抛出GeneratorExit异常。当在生成器内部捕获到此异常后必须重新抛出GeneratorExit或者StopIteration异常以使生成器正常结束,如果没有重新抛出而是返回一个值的话将触发RuntimeError异常。对一个生成器多次调用close()不会产生错误。
Rise our ability!
生成器方法(generator function)作为一个可选特性在Python2.2中首次出现,2.3版本中内置支持了此特性,yield成为了关键字,生成器在后续版本中得到增强(比如增加了异常处理等特性)。C#2.0中也引入类似特性(迭代器),这两者之间有不少相似之处。本文针对IronPython 2.0 beta3进行讨论。
浙公网安备 33010602011771号