在Python中,我们将带有 yield 的函数称之为 generator(生成器)。generator可以一边循环一边计算,是可迭代对象,也就是说可以使用for循环来迭代出generator的各个值。
一、
一般为了说明generator,都会使用斐波那契数列来举例,这里也不例外:
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
yield b
a, b = b, a + b
n = n + 1
如结果所示,调用 fab(5) 并不会执行 fab 函数,而是返回一个 可迭代对象, 每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,函数继续执行,直到再次遇到 yield或return。
在一个 generator中,如果没有 return,则默认执行至函数完毕,如果在执行过程中遇见了return,则直接抛出 StopIteration 终止迭代。
二、
与generator有关的很重要的函数有next()和send(parameter)。
因为generator是可迭代对象,我们可以使用next()来手动迭代其各个值。仍然拿上面fab()函数来举例,如下图所示:
send(parameter)函数可以给yield表达式传值,而next()只能传递None进去。因此,某种程度上c.next() 和 c.send(None)的作用是一样的。来看例子:
可以看到,认为n=5、m=10是错误的!这是因为yield是一个表达式,(yield 5)本身是有一个返回值的,这个返回值可以由send(parameter)函数传递进去:
需要注意的是,第一次调用时不能使用send发送一个非None值,否则会报错,因为没有yield语句来接收这个值。可以使用next()语句或send(None)。
send(parameter) 和 next()这两个函数是有其自己的返回值的,它们的返回值很特殊,返回的是下一个yield表达式的参数。比如yield 5,则返回5。
因为for循环迭代generator时,其实是一次次调用了next()函数,直到抛出StopIteration异常为止。而每次迭代出的值,其实就是next()函数的返回值,也就是yield表达式的参数!