一.生成器:
生成器的实质就是迭代器
在python中有三种方式获取生成器:
1.通过生成器函数
2.通过各种推导式来实现生成器
3.通过数据的转换也可以获取生成器
二.通过生成器函数获取生成器:
def func(): print('哈哈') yield '呵呵' #有yield就是生成器 ret = func() #通过函数来创建一个生成器即生成器函数被执行,获取的是生成器,而不是函数的执行 print(ret) #返回的值是个地址就是个生成器 结果:<generator object func at 0x0000000000B99D00>
就是将函数中的return换成yield就是生成器,
return:直接返回结果,结束函数的调用
yield:返回结果,可以让函数分段执行.
1.如何执行生成器:
1)生成器的本质就是迭代器,所以可以用__next__()进行执行
def func(): print('周杰伦') yield '昆凌' print('哈哈') yield '呵呵' ret = func() print(ret.__next__()) print(ret.__next__()) 结果:周杰伦 昆凌 哈哈 呵呵
注意:如果最后一个yield执行完毕,再次__next__()程序会报错
生成器的作用:省内存,可以一次去一个,一个个的指向下一个,不会回去,__next__()到哪,指针就指哪,下一次继续获取指针指向的值.
2.用send()方法:
def eat(): print('我吃什么') a = yield '馒头' print('a=',a) b = yield'大饼' print('b=',b) c = yield'韭菜盒子' print('c=',c) yield 'GAME OVER' gen = eat() #获取生成器 print(gen.__next__()) print(gen.send('胡辣汤')) print(gen.send('狗粮')) print(gen.send('猫粮')) 结果:我吃什么 馒头 a= 胡辣汤 大饼 b= 狗粮 韭菜盒子 c= 猫粮 GAME OVER
send 和 __next__区别
1).send和next()都是让生成器向下走一次
2).send可以给上一个yield的位置传递值,不能给最后一个yield发送值,第一次执行生成器代码的时候不能使用send()
3.生成器本质上是迭代器,所以可以使用for循环取值
def func(): print('哈哈') yield '呵呵' print('嘿嘿') yield '嘻嘻' print('呀呀') yield'花花' ret = func() for i in ret: print(i)
4.可以用列表list取值:
def func(): print('哈哈') yield '呵呵' print('嘿嘿') yield '嘻嘻' print('呀呀') yield'花花' ret = func() print(list(ret)) 结果:哈哈 嘿嘿 呀呀 ['呵呵', '嘻嘻', '花花']
三.列表推导式,生成器表达式以及其他推导式
1)列表推导式:[结果 for 变量 in 可迭代对象 if 筛选]
例:给一个列表,通过循环,向列表中添加1-9
lst = [] for i in range(1,10) lst.append(i) print(lst)
通过列表推导式:
lst = [i = for i in range(1,10)] print(lst)
对列表中的数据进行筛选:[结果 for 变量 in 可迭代对象 if条件]
lst = [i fro i in range(1,101) if i%2 == 0] print(lst)
2)生成器表达式:
生成器表达式和列表推导式的语法基本上一样,只是把[]替换()
gen = (i for i in range(100)) print(gen) 结果:<generator object <genexpr> at 0x0000000000A29D00>
打印结果是个生成器,可以用for循环来获取最终结果
gen = (i for i in range(100)) for i in gen: print(i)
生成器表达式也可以进行筛选,跟列表表达式一样,只是[]变成了()
生成器表达式和列表推导式的区别:
1.列表推导式比较耗内存,一次性加载,生成器表达式几乎不占内存,使用的时候才分配和使用内存.
2.得到的值不一样,列表推导式得到的是一个列表,生成器表达式获取的是一个生成器
生成器的惰性机制:生成器只有在访问的时候才取值,说白了,你找他要他才给你值,不找他要,他就不回执行.
def func(): print(111) yield 222 g = func() # 生成器g g1 = (i for i in g) # 生成器g1. 但是g1的数据来源于g g2 = (i for i in g1) # 生成器g2. 来源g1 print(list(g)) # 获取g中的数据. 这时func()才会被执行. 打印111.获取到222. g完毕. print(list(g1)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1 也就没有数据了 print(list(g2)) # 和g1同理
神坑:生成器,要值的时候才拿值
3)字典推导式{结果 for 变量 in可迭代对象 if 筛选} 结果--->key:value
dic = {'a':'b','c':'d'}
把字典中的key和value互换
dic = {"a":"b", "c":"d"} new_dic = {dic[key]:key for key in dic } print(new_dic)
4)集合推导式:{结果 for 变量 in 可迭代对象 if 筛选} 结果--->key
集合推导式可以直接生成一个集合,集合特别,无序,不重复,所以集合推导式自带去重功能
lst = ["马化腾", "马化腾", "王建忠", "张建忠", "张建忠", "张雪峰", "张雪峰"] s = {i for i in lst} # 集合推倒式 print(s)
总结:推导式有:列表推导式,字典推导式,集合推导式,没有元祖推导式
生成器表达式:(结果 for 变量 in 可迭代对象 if 筛选)
生成器表达式可以直接获取到生成器对象,生成器可以直接进行for循环,生成器具有惰性机制