之前了解了生成器的概念,带有 yield 的函数在 Python 中被称之为 generator(生成器),那么应该什么时候使用呢?
举个例子:
简单输出斐波那契數列前 N 个数
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
执行 ,我们可以得到如下输出:
结果没有问题,但有直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List。
如下:
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)
改写后的 fab 函数通过返回 List 能满足复用性的要求,但该函数在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代。
如下:
for i in range(1000):
pass
如果我们想要保持第一种 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了:
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print(b)
a, b = b, a + b
n = n + 1
总结
- yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator
- 比如 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象。
- 在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。