1.yield的基本使用
yield的作用是将一个函数转换成一个迭代器,并且程序再次进入这个函数时候,是从这个函数的yield语句的下一句开始执行的。
#测试代码:
def yield_test(n):
for i in range(n):
yield i
call(i)
print('i=',i)
def call(n):
return n*2
for i in yield_test(5):
print(i)
运行的结果如下:
0
i= 0
1
i= 1
2
i= 2
3
i= 3
4
i= 4
2.yield的深入——从斐波那契数列说起
斐波那契数列是:第一个为1,第二个为1,第三个往后开始,每一个为前两个的和。
- 基本实现:
def fab(n):
x,y,z=1,1,0
while z<n:
print(x)
x,y = y,x+y
z+=1
fab(7)
运行结果:
1
1
2
3
5
8
13
这个函数因为其内部存在一个print函数,他的可复用性差,也就是说这个函数如果被别人调用,其返回值是一个None,不是一个数列,可能只适合看看,不适合其他函数对该函数生成序列的调用。
为此提出第二个版本
def fab2(n):
x,y,z = 1,1,0
list1=list()
while z<n:
list1.append(x)
x,y = y , x+y
z+=1
return list1
fab2(7)
v2版本在执行fab2(n)返回的list类型的斐波那契数列。满足复用性的要求,但是如果函数中的n很大,list会占用很大的内存,如果为了控制内存的占用,提出使用v3版本
def fab3(n):
x,y,z = 1,1,0
while z<n:
yield x
x,y = y,x+y
z+=1
for i in fab3(5):
print(i)
第三个版本的运行方式:fab3(5)函数中因为存在yield,导致fab3(5)函数变成了迭代器,当for i fab3(5),运行流程如下图:
从第5步,开始直接跳到了yield x后面这一句开始执行。这样内存占用会很小。
这里了要注意:
- fab3是一个迭代函数 generator function,而fab3(5)是类似于实例化的一个迭代器,fab3是无法迭代的,而fab3(5)是可以迭代的。
- 在迭代函数有执行的时候,如果遇到return,则直接抛出 StopIteration 终止迭代,如果没有return默认执行到函数结束
yield的另一个作用是用来对文件的读取。如果对文件直接采用read(),会导致不可预测的内存占用,一个好的方法是利用一个固定长度的缓存区去不断的读取文件的内容,通过yield方法可以很容易的实现。
def read_file(fpath):
Blocksize = 1024
with open(fpath,'rb') as f:
while True:
block = f.read(Blocksize)
if block:
yield Block
else:
return
后续会持续更新,欢迎大家批评指正