生成器是由迭代器进化而来,所以生成器对象有 __iter__
和 __next__
方法,可以使用 for 循环获得值,注意这里所说的 “获得值” 指的是下文代码块里 yield 语句中 yield 关键字后面的 i 。这是在 Python 2.5 时出现的特性,在 Python 3.3 中出现 yield from 语法之前,生成器没有太大用途。但此时 yield 关键字还是实现了一些特性,且至关重要,就是生成器对象有 send 、throw 和 close 方法。这三个方法的作用分别是发送数据给生成器并赋值给 yield 语句、向生成器中抛入异常由生成器内部处理、终止生成器。这三个方法使得生成器进化成协程。
生成器(或协程)有四种存在状态:
GEN_CREATED 创建完成,等待执行
GEN_RUNNING 解释器正在执行(这个状态在下面的示例程序中无法看到)
GEN_SUSPENDED 在 yield 表达式处暂停
GEN_CLOSE 执行结束,生成器停止
可以使用 inspect.getgeneratorstate
方法查看协程的当前状态,举例如下:
In [202]: import inspect In [203]: def generator(): ...: i = '激活生成器' ...: while True: ...: try: ...: value = yield i ...: except ValueError: ...: print('OVER') ...: i = value ...: In [204]: g = generator() # 1 In [205]: inspect.getgeneratorstate(g) # 2 Out[205]: 'GEN_CREATED' In [206]: next(g) # 3 Out[206]: '激活生成器' In [207]: inspect.getgeneratorstate(g) Out[207]: 'GEN_SUSPENDED' In [208]: g.send('Hello Shiyanlou') # 4 Out[208]: 'Hello Shiyanlou' In [209]: g.throw(ValueError) # 5 OVER Out[209]: 'Hello Shiyanlou' In [210]: g.close() # 6 In [211]: inspect.getgeneratorstate(g) Out[211]: 'GEN_CLOSED' In [212]:
代码说明如下:
1、创建生成器
2、查看生成器状态
3、这步操作叫做预激生成器(或协程),这是必须要做的。在生成器创建完成后,需要将其第一次运行到 yield 语句处暂停
4、暂停状态的生成器可以使用 send 方法发送数据,此方法的参数就是 yield 表达式的值,也就是 yield 表达式等号前面的 value 变量的值变成 'Hello Shiyanlou',继续向下执行完一次 while 循环,变量 i 被赋值,继续运行下一次循环,yield 表达式弹出变量 i
5、向生成器抛入异常,异常会被 try except 捕获,作进一步处理
6、close 方法终止生成器,异常不会被抛出
因为生成器的调用方也就是程序员自己可以控制生成器的启动、暂停、终止,而且可以向生成器内部传入数据,所以这种生成器又叫做协程,generator 函数既可以叫做生成器函数,也可以叫协程函数,这是生成器向协程的过渡阶段。