kimber_kimber

导航

python--生成器

定义:带有yield 的方法称为生成器 generator ,生成器会返回一个迭代器

    可以理解为生成器就是一个迭代器 

yield 的功能有两个  第一是return , 另一个功能是接收值 (后面send()函数会讲)

1. 一个简单的生成器的例子 

  

 1 def fun():
 2     print('start......')
 3     a=1
 4     while True:
 5         a += 1
 6         yield a
 7         print('yield 后 a=',a)
 8 
 7 if __name__=='__main__':
11     f = fun()
12     print('fun的返回类型为',type(f))
13     print('第一次next:',next(f))
14     print('第二次next:',next(f))

运行结果:

fun的返回类型为 <class 'generator'>
start......
第一次next: 2
yield 后 a= 2
第二次next: 3

分析:

f=fun() 不会运行函数,而是返回一个迭代器 
next(f) 这一行开始调用fun 函数,运行到yield ,return a,(此时a=2),记住了运行的位置
下一个next() 从yield的下一行运行 print('yield 后 a=',a)

2.遍历方式:for 循环去遍历,也可以用next() 实现继续运行的效果

 1 def fun():
 2     print('start......')
 3     a=1
 4     while True:
 5         a += 1
 6         yield a
 7         print('yield 后 a=',a)
 8         if a==3:
 9             break
10 
11 if __name__=='__main__':
12     f = fun()
13     for i in f:
14         print(i)

运行结果:

start......
2
yield 后 a= 2
3
yield 后 a= 3

3.生成器的send()函数 

yield 的作用有2个,第一个是我们上面看到的可以类似于 return ,返回一个值出来。
另外一个功能是可以接收外部传过去的值,给 yield 传值需用到send() 方法

  

def fun():
    num = 1
    print('first-----',num)
    name1 =yield 1
    print('second-----',name1)
    name2 =yield 3
    print('third------',name2)
    yield num

if __name__=='__main__':
    f = fun()
    print(f.__next__())
    print(f.__next__())
    print(f.send('yoyo'))

运行结果:

first----- 1
1
second----- None
3
third------ yoyo
1

我们可以这样理解:send()方法把值给到yield, yield赋值给name2,于是就可以看到上面的结果了。

name1 因为未赋值,所以返回了None 

当调用send() 方法的时候,实际上是有2个功能的:

  • 1.赋值给到yield的

  • 2.执行了一次.__next__()方法,或next()函数  

也可以这样写

  if __name__='__main__'  :
    print(f.send(None))#等价于 f.__next__()/next(f)
    print(f.send('yoyo'))
    print(f.send('kim'))

第一行 send(None) 等价于 f.__next__()/next(f)

4.应用场景:

  1.斐波那契数列

def func(max):
    n1,n2,count=0,1,1
    while count<max:
        yield count
        n1,n2=n2,count
        count=n1+n2

def test_fun():
    #if __name__=='__main__':
    f=func(100)
    for i in f:
        print(i,end=',')

输出结果:1,2,3,5,8,13,21,34,55,89,

 

  2.读取大文件

如果直接对文件对象调用read () 函数,会导致不可预测的内存占用,可以利用固定长度的缓冲区,结合yield 进行文件的读取

1 def readFile(fpath):
2     BLOCK_SIZE=1024
3     with open(fpath,'rb') as f:
4         BLOCK=f.read(BLOCK_SIZE)
5         if BLOCK:
6             yield BLOCK
7         else:
8             return 

 

posted on 2021-03-04 00:55  kimber_kimber  阅读(24)  评论(0编辑  收藏  举报