yield
是用来简化以下场景:函数来生成序列,并且使用遍历的方式来访问序列中的元素。
yield
的实现原理理解上来说在调用yield
时Python会保留函数的现场,当再次遍历时函数的状态不丢失,可以继续生成。
经典的例子斐波那契数列
问题描述
返回斐波那契数列前n个元素
Python解法
第一个版本:朴素实现
1
2
3
4
5
6
7
8
9
| def fab(n):
fab_list = list()
i = 0
a, b = 0, 1
while i < n:
a, b = b, a+b
fab_list.append(a)
i = i + 1
return fab_list
|
第一个版本是遍历并保存所有前n项斐波那契数列的元素。最大的问题是会占用非常多的内存,当调用fab(10000)时,在我的电脑中已经是无法完成的了。
第二个版本: 简单的迭代器实现
实现一个迭代器类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class Fab(object):
def __init__(self, n):
self.n = n
self.a, self.b = 0, 1
self.i = 0
def __iter__(self):
return self
def next(self):
if self.i < self.n:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.i = self.i + 1
return r
raise StopIteration()
if __name__ == '__main__':
for i in Fab(5):
print i
|
第二个版本实现了迭代器,每次调用时再生成下一个元素,因此对内存的占用是恒定值。但缺点是代码很长,不够易读。
第三个版本:yield方法
1
2
3
4
5
6
7
8
9
10
| def fab(n):
i, a, b = 0, 0, 1
while i < n:
a, b = b, a+b
yield a
i = i + 1
if __name__ == '__main__':
for n in fab(5):
print n
print fab(5)
|
第三种yield方法兼具了第一种的简洁,第二种的高效。
fab(5)
返回的是一个generator
对象——让一个函数像iterator那样工作,这样在遍历的场景下既可以保持代码简洁,又保持了内存使用的高效。
相关介绍链接
- Improve Your Python: ‘yield’ and Generators Explained
- Python yield 使用浅析