一、生成器和协同程序
1. 生成器
- 生成器是迭代器的一种实现,它是为了让python更加简洁,因为迭代器需要我们自己去定义一个类和实现相关的方法,而生成器则只需要在普通的函数中加一个 yield 语句即可
- 简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator
- 生成器不像 return 那样返回值,而是每次产生多个值。每次产生一个值(使用 yield语句),函数就会被冻结。即函数停在那点等待被重新唤醒,函数被重新唤醒后就从停止的那点开始执行
- 生成器被调用时,在函数体中的代码不会被执行,而会返回一个迭代器,每次请求一个值,就会执行生成器中的代码,直到遇到一个 yield 或 return语句。
return 语句意味着生成器要停止执行(不再生成任何东西,return语句只有在一个生成器中使用时才能进行无参数调用)
2. 协同程序
- 生成器的发明使得python模仿协同程序的概念得以实现。所谓协同程序就是可以运行的独立函数调用,函数可以暂停或者挂起,并在需要的时候从程序离开的地方继续或者重新开始
- 对于调用一个普通的Python函数,一般是从函数的第一行代码开始执行,结束于return语句、异常或者函数所有语句执行完毕。一旦函数将控制权交给调用者,就意味着全部结束。函数中的所有工作以及保存在局部变量中的数据都将丢失。再次调用这个函数都将从头创建。
- Python是通过生成器来实现类似于协同程序的概念:生成器可以暂时挂起函数,并保留函数的局部变量等数据,然后再次调用时,从上次暂停的位置继续执行下去
二、示例
- 示例 1
当函数结束时,一个StopIteration异常会被抛出 - 示例 2
有python中for循环会自动调用next()方法和处理StopIteration异常,所有for循环也是可以对生成器产生作用
- 示例3
def fabs():
a = 0
b = 1
while True:
a,b = b,a+b
yield a
for each in fabs():
if each > 20:
break
print(each)
调用 fabs() 不会执行 fab 函数,而是返回一个 iterable 对象!
在 for 循环执行时,每次循环都会执行 fabs()函数内部的代码,执行到 yield a时,fab 函数就返回一个迭代值。
下次迭代时,代码从 yield a 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。
三、补充
- 使用生成器,实际上是将函数运行所有的结果以一个迭代器的形式返回