Python yield
在 Python 中,使用了 yield
的函数被称为生成器 (generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单的理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield
时函数会暂停并保存当前所有的运行信息,返回 yield 的值,并在下一次执行 next()
方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。
实例:斐波那契数列
斐波那契数列是一个简单的递归,除第一个和第二个数外,任意一个数可由前两个数相加得到。
方法1:简单输出斐波那契数列的前 N 个数
def fab(max):
n, a, b = 0, 0, 1
for n in range(max):
print(b)
a, b = b, a+b
n = n+1
fab(5)
输出:
1
1
2
3
5
使用 print 打印导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法调用。
方法2:通过列表返回
def fab(max):
n, a, b = 0, 0, 1
L = []
for n in range(max):
L.append(b)
a, b = b, a+b
n = n+1
return L
for i in fab(5):
print(i)
输出:
1
1
2
3
5
返回 list 能满足复用性要求,但该函数在运行中占用的内存会随着参数 max 的增大而增大。
如果要控制内存,不要用 List 来保存中间结果,而是通过 iterable
来迭代。
方法3:通过 iterable 对象来迭代
利用 iterable 把 fab 函数改写为一个 iterable 的 class。
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)
输出:
1
1
2
3
5
Fab 类通过 __next()__
不断返回数列的下一个数,内存占用始终为常数。
但是 class 改写的版本,代码比较繁琐。
既想保持代码的简洁,又想获得 iterable 的效果,使用 yield
。
方法4:yield
def fab(max):
n, a, b = 0, 0, 1
for n in range(max):
yield b
a, b = b, a+b
n += 1
for n in fab(5):
print(n)
输出:
1
1
2
3
5
仅把第一种方法的 print(b)
改为 yield b
,即保持了代码的简洁性又获得了 iterable 的效果。