生成器的本质就是迭代器,因为生成器含有__iter__()方法和__next__()方法;
带有yield关键字的函数都是生成器函数,生成器函数被调用时会返回一个生成器,但是函数体内的代码不会被执行,只有生成器调用__next__()方法时,才会被执行,但是遇到yied关键字处,函数就暂停,等下一次该生成器再调用.__next__()函数时,下面的代码才会被继续执行;
其实生成器效率还是比较高的(个人理解),比如我们现在需要打印“哈哈哈哈哈”,需要打印200万,如果使用list存储,然后再打印,简直太浪费内存了,我们不可能一次存储完所有之后,再一次性全部打印,就好像QQ聊天,我们 输入一段内容,及时发送给i对方,而不是等所有内容编辑完成一次性发给别人;
def generator(): for i in range(2000000): yield "哈哈哈哈%d"%i g=generator() for i in g: print(i)
运行结果:
生成器就是边调用边取值~
生成器函数获取值的三种方法:
1.可以使用.__next__()方法调用来获取一个值;
2.也可以使用for循环,来打印出所有的值;
3.当然也可以使用强制类型转换(比如list(generator)就会打印出生成器所有的值)-------占用内存
写一个生成器,实现:有一个文件,从文件中分段读取内容可以一行一行读,也可以几个字节读取,要求读出来的结果前面加上*****在返回给调用者;
def generator(): with open("info",mode='r',encoding='utf-8') as file: while True: line=file.readline() # line=file.read(20) if line.strip(): yield "*****"+line.strip() g=generator() for i in g: print(i)
运行结果:
send()方法
讲send()方法之前,先来看一段代码:
def generator(): print('a') yield 1 print('b') yield 2 print('3') g=generator() print(g.__next__()) print(g.__next__()) print(g.__next__())
运行结果:
虽然最后一个yield后面的代码print(3)被打印了,可是却报错了,因为执行了三个.__next__() 然而生成器函数内部只有两个yield可以被__next__()方法调用~
所以一般不要再最后一个yield后面写代码,会报错;
但是使用for 循环打印却不会报错,而且还可以输出最后一个yield后面的代码呢~
def generator(): print('a') yield 1 print('b') yield 2 print('3') g=generator() for i in g: print(i)
运行结果:
现在来看send()方法:
def generator(): print('a') yield 1 print("b") yield 2 g=generator() print(g.__next__()) print(g.send(None))
运行结果:
1. 从运行结果上来看,send()方法和.__next__()方法是一样的,都是可以从上一个yield位置之后的代码开始执行,遇到下一个yield就停止,将值返回给g.__next__()或者g.send()处,以便打印;
def generator(): print('a') value=yield 1 print(value) print('b') yield 2 g=generator() print(g.__next__()) print(g.send('我可以把值返回给上一个yield停止的位置处'))
运行结果:
执行过程是这样的:首先g.__next__()方法会从函数体开始执行,然后遇到第一个yield就停止,然后g.send()方法开始执行,从上一个yield停止的位置开始,然后把值传给上一个yield停止的位置也就是value(因为value=yield 1遇到赋值号,先执行等号右侧,然后在进行赋值,__next__()方法刚好执行到等号右侧就停止了,send()方法接着从停止的位置执行,就会把里面的值传递给赋值号左边,然后继续执行后面的代码,知道遇到下一个yield就停止了,将yield的结果返回,这一点跟__next__()方法很像~)
也就是 2.send()方法除了可以跟__next__()方法一样从上一个yield停止的地方开始执行,一直到下一个yield的地方停止外,还可以对上一个yield停止的位置处传数据!!
最后需要注意的是,3.生成器在取值时,第一个值必须由.__next__()方法获得;最后一个yield不传值!!因为你传值,后面也没有yield了 也就没法用__next__()方法或者send()方法取值了
除非:
def generator(): print('a') value1=yield 1 print('send()方法给在第一个yield处传递的值',value1) print('b') value2=yield 2 print("send()在第二个yield处传递的值",value2) yield g=generator() print(g.__next__()) print(g.send('哈哈哈')) g.send('嘻嘻嘻')
运行结果: