python函数式生成器的简单介绍( 二 )


1. 迭代器协议
由于生成器自动实现了迭代器协议,而迭代器协议对很多人来说,也是一个较为抽象的概念 。所以 , 为了
更好的理解生成器,我们需要简单的回顾一下迭代器协议的概念 。
1. 迭代器协议是指:对象需要提供next方法 , 它要么返回迭代中的下一项,要么就引起一个
StopIteration异常,以终止迭代
2. 可迭代对象就是:实现了迭代器协议的对象
3. 协议是一种约定 , 可迭代对象实现迭代器协议,Python的内置工具(如for循环,sum,min,max函
数等)使用迭代器协议访问对象 。
举个例子:在所有语言中,我们都可以使用for循环来遍历数组,Python的list底层实现是一个数组,所
以,我们可以使用for循环来遍历list 。如下所示:
for n in [1, 2, 3, 4]:
... print n
但是,对Python稍微熟悉一点的朋友应该知道,Python的for循环不但可以用来遍历list,还可以用来遍历
文件对象,如下所示:
with open(‘/etc/passwd’) as f: # 文件对象提供迭代器协议
... for line in f: # for循环使用迭代器协议访问文件
... print line
...
为什么在Python中,文件还可以使用for循环进行遍历呢?这是因为,在Python中,文件对象实现了迭代
器协议,for循环并不知道它遍历的是一个文件对象,它只管使用迭代器协议访问对象即可 。正是由于
Python的文件对象实现了迭代器协议,我们才得以使用如此方便的方式访问文件,如下所示:
f = open('/etc/passwd')
dir(f)
['__class__', '__enter__', '__exit__', '__iter__', '__new__', 'writelines', '...'
2. 生成器
Python使用生成器对延迟操作提供了支持 。所谓延迟操作 , 是指在需要的时候才产生结果,而不是立即产
生结果 。这也是生成器的主要好处 。
Python有两种不同的方式提供生成器:
2017/11/6 如何更好地理解Python迭代器和生成器? - 知乎
2/5
1. 生成器函数:常规函数定义 , 但是,使用yield语句而不是return语句返回结果 。yield语句一次返回一
个结果,在每个结果中间 , 挂起函数的状态 , 以便下次重它离开的地方继续执行
2. 生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个
结果列表
2.1 生成器函数
我们来看一个例子,使用生成器返回自然数的平方(注意返回的是多个值):
def gensquares(N):
for i in range(N):
yield i ** 2
for item in gensquares(5):
print item,
使用普通函数:
def gensquares(N):
res = []
for i in range(N):
res.append(i*i)
return res
for item in gensquares(5):
print item,
可以看到 , 使用生成器函数代码量更少 。
2.2 生成器表达式
使用列表推导,将会一次产生所有结果:
squares = [x**2 for x in range(5)]
squares
[0, 1, 4, 9, 16]
将列表推导的中括号 , 替换成圆括号,就是一个生成器表达式:
squares = (x**2 for x in range(5))
squares next(squares)
next(squares)
1
next(squares)
4
list(squares)
[9, 16]
Python不但使用迭代器协议,让for循环变得更加通用 。大部分内置函数,也是使用迭代器协议访问对象
的 。例如,sum函数是Python的内置函数,该函数使用迭代器协议访问对象 , 而生成器实现了迭代器协
2017/11/6 如何更好地理解Python迭代器和生成器? - 知乎
3/5
议,所以,我们可以直接这样计算一系列值的和:

推荐阅读