# 通过`yield`来创建生成器
def func():
for i in range(10):
yield i
>>> f # 此时生成器还没有运行
<generator object func at 0x7fe01a853820>
>>> f.__next__() # 当i=0时,遇到yield关键字,直接返回
0
>>> f.__next__() # 继续上一次执行的位置,进入下一层循环
1
---------------------------------------------------
# 通过列表来创建生成器
[i for i in range(10)]
#除了next函数,生成器还支持send函数。该函数可以向生成器传递参数。
'''清单 1. 简单输出斐波那契數列前 N 个数'''
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print (b)
a, b = b, a + b
n = n + 1
fab(10)
'''
有经验的开发者会指出,直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。
要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List。以下是 fab 函数改写后的第二个版本:
清单 2. 输出斐波那契數列前 N 个数第二版'''
def fab1(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
print(L)
return L
fab1(10)
print('*'*20)
'''
class 改写的这个版本,代码远远没有第一版的 fab 函数来得简洁。如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了:
清单 5. 使用 yield 的第四版'''
def fab4(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print b
a, b = b, a + b
n = n + 1
print(fab4(10)) #同一地址
for n in fab4(5):
print(n)
print(fab4(5))
fab 和 fab(5),fab 是一个 generator function,而 fab(5) 是调用 fab 返回的一个 generator,好比类的定义和类的实例的区别。
2、另一个 yield 的例子来源于文件读取。如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取:
def read_file(fpath):
BLOCK_SIZE = 1024
with open(fpath, 'rb') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return