本文参考自:http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
以斐波那契数列的实现来说明这个问题:
demo1:
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
for n in fab(5):
print n
一般来讲,我们都会写成上边程序的样子,这样既实现了基本功能,又可以复用,基本符合要求了。
但是如果max是1000w或者更大呢,那么存储在list中将会占据很大的内存。常见的情况还包括一下消耗大量内存的做法:
for line in open("test.txt").readlines():
print line
#这种做法是将文件的中的内容一次全部读取到内存中,每次从内存中取出一行然后输出,如果文件内容太大,将消耗大量的内存。
for line in open("test.txt"):
print line
#这种做好就好多了,既简单又不节省内存,利用迭代器来每次读取一行数据。
for i in range(1000): pass
#会产生一个1000个元素的list
for i in xrange(1000): pass
#xrange()产生的是一个迭代对象,而不是一个1000个元素的list, 每次迭代返回下一个数值
上面两个小对比,是我们平时写程序时不是很注意的地方,但是当你读到这之后,以后写程序不光要考虑怎么实现,而且要写出更优秀的代码来。
然后继续我们的斐波那契数列:
demo2:
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration()
for n in Fab(5):
print n
demo3:
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
for n in fab(5):
print n
简单来讲:yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。(照抄的参考文章)
个人理解: 是不是就是实时调用的意思,什么时候执行next什么时候执行一次fab函数,但是上一次的值都在内存中存储。而不是一次将所有的结果求出放在list中。
更多细节请参考本文一开头给出的文章链接, 下面我再补充一下关于迭代器和生成器的理解:
生成器:生成器(Generator)是创建迭代器的简单而强大的工具
迭代器:
1、对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式
2、它不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。
具体的理解以及内部是如何工作的,大体可以参照:http://www.jb51.net/article/73939.htm
如果想更身体的了解迭代协议等内容,可以自行学习。