在阅读这篇文章以前,你应该已经了解Python中的迭代器。如果不清楚的话,可以参考我的另一篇文章:《Python高级编程之初识迭代器》
1. yield语句
在之前的文章中,我们使用类来创建自己的迭代器,实现过程稍微麻烦一点:
class yrange:
def __init__(self, start=0, stop=0):
self.start = start
self.stop = stop
def __iter__(self):
return self
def next(self):
if(self.start < self.stop):
start = self.start
self.start += 1
return start
else:
raise StopIteration
生成器函数可以简化迭代器的创建。只要在函数中使用 yield
语句来替代结果的输出,就变成了一个生成器函数。
下面的代码实现了与上述的类等价的功能
def zrange(start=0, stop=0):
while start < stop:
yield start
start += 1
可以看到,实现的过程非常简洁。
2. 生成器
生成器的工作方式与迭代器相同,可以被视为是迭代器的一种。需要注意的是,生成器只支持一遍的迭代。当一个生成器被迭代完之后,就无法再产生结果,此时必须使用一个新的生成器以便再次迭代。
如果我们调用上面示例中定义的生成器函数,将会得到一个生成器。
>>> zrange(0, 10)
<generator object zrange at 0x03910BC0>
我们可以像使用其它迭代器一样使用生成器。
>>> for z in zrange(5, 8):
... print z
5
6
7
3. 生成器函数工作原理
生成器函数与普通函数最显著的不同就是它没有 return
语句,取而代之的是 yield
语句。
正常的函数在被调用后,会通过 return
语句返回一个值,然后结束。而生成器函数被调用后,返回的生成器类似于一个函数环境,每次迭代过程中执行到 yield
语句,就会返回一个值,然后挂起函数,等下一次迭代时再恢复函数的状态,继续执行其它语句,直到再次遇到 yield
语句时重复上述过程。
我们用一个例子来观察生成器函数的运行过程:
>>> def gen(stop):
... start = 0
... print "Generator starts"
... while(start < stop):
... print "Before", start
... yield start
... print "After", start
... start += 1
... print "Generator stops"
>>> G = gen(3)
>>> G.next()
Generator starts
Before 0
0
>>> G.next()
After 0
Before 1
1
>>> G.next()
After 1
Before 2
2
>>> G.next()
After 2
Generator stops
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
StopIteration
可以看到,每次执行到 yield
语句,函数将被挂起,在下次迭代时函数恢复,继续执行。
在迭代到达末尾时,生成器触发了 StopIteration
异常,遵循迭代协议。单从生成器的工作方式来看,与迭代器是一样的。
4. 生成器表达式
除了通过生成器函数来得到生成器之外,还可以使用生成器表达式来实现。
生成器表达式与列表推导式的语法一致,不同之处在于生成器表达式使用一对圆括号来包围表达式,而列表推导式使用的是方括号。
生成器表达式的基本用法如下:
>>> L = [1, 2, 3]
>>> G = (x ** 2 for x in L)
变量 G
就是我们得到的生成器,下面对它进行迭代
>>> for i in G:
... print i
1
4
9
这里只提到了生成器表达式最简单的语法,如果要更深入了解生成器表达式,可以参考具有相同语法的列表推导式,只要把表达式的方括号替换为圆括号即可。
详细介绍请参考:《Python高级编程之列表推导式》
作者:Wray Zheng
原文:http://www.codebelief.com/article/2017/02/python-advanced-programming-generator/