python中的生成器主要经历三个发展阶段:
- 作为实现迭代器协议的一种方式而出现(yield语句)
- 增添方法,使生成器能够支持协程(增加close,send,throw方法,调整yield语句为yield表达式)
- 为了重构方便增加了yield from 语法
在这篇博文中,主要介绍用于第一点的生成器
实现迭代器协议的方法
假设你有一个文件,你需要为文件的每一行添加两边添加上<p> 标签
类方法实现迭代器协议
1 | class addPC(object): |
上面这个类实现了迭代器协议,可以在for里面使用
1 | for line in addPC("ok.txt"): |
使用yield语法实现迭代器
1 | def addP(filename): |
来看看一个generator object 拥有的行为
1 | In [19]: gen_obj = addP("ok.txt") # addP("ok.txt") 返回的是一个generator object |
其中,像addP这种包含yield的函数称为generator function,调用generator function得到的返回值是一个generator object;而一个generator object实现了迭代器协议(__iter__方法和next方法),所以一个generator object可以出现在一切需要可迭代对象的地方, 例如:for语句中,next、iter函数的参数,等等。
通过使用yield,我们可以将不同的next方法调用之间的全局变量的操作变成对局部变量的操作
yield的限制
与return 共存
需要说明的是,在pep325之后,不存在这条限制
允许不带参数的return语句存在generator function中,代表这generator将会抛出一个StopIteration异常
不可在try/finally结构的try分句中使用
需要说明的是,在pep325之后,不存在这条限制
在当时,pep255给出的理由是,由于try/finally结构用于确保占用资源(fd之类的系统资源)的释放,如果在try分句中出现了yield, 无法保证finally语句中的代码块被执行
小结
- 生成器最初是实现迭代器的一个简化的方法
- 包含了yield语句的函数就是generator function, generator function的调用返回值是一个generator object
1 | class TreeNode: |