生成器和生成器表达式
一:生成器
生成器实质上就是迭代器。
三种方式获取生成器: 01:通过生成器函数 02:通过各种推导式实现生成器 03:通过数据的转换也可以获取生成器
eg:普通函数 def fun() print("111") return ret=func() print(ret) 结果: 111 222
将函数的return 换成yield 就是生成器 def fun() print("111") yield ret=func() print(ret) 结果:<generator object func at 0x10567ff68> 打印结果:结果是一个函数名字的内存地址
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
原因:由于函数中存在了yield. 那么这个函数就是⼀个⽣成器 函数. 这个时候. 我们再执⾏这个函数的时候. 就不再是函数的执⾏了. ⽽是获取这个⽣成器.如何使⽤呢? 想想迭代器. ⽣成器的本质是迭代器. 所以. 我们可以直接执⾏__next__()来执⾏ 其实return和yield一样都有返回值,return返回值后,就退出函数,后面的函数就不在执行 yield 则是在返回 返回值后 ,还给上一个yield 的变量赋值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
例如: def eat(): print("我吃什么啊") a = yield "馒头" print("a=",a) b = yield "⼤饼" print("b=",b) c = yield "⾲菜盒⼦" print("c=",c) yield "GAME OVER" gen = eat() # 获取⽣成器 ret1 = gen.__next__() print(ret1) ret2 = gen.send("胡辣汤") print(ret2) ret3 = gen.send("狗粮") print(ret3) ret4 = gen.send("猫粮") print(ret4) 打印结果:send和__next__()区别: 1. send和next()都是让⽣成器向下走⼀次 2. send可以给上⼀个yield的位置传递值, 不能给最后⼀个yield发送值. 在第⼀次执⾏⽣ 成器代码的时候不能使⽤send()
二:生成器的作用:
生成器可以用for循环来循环获取内部的元素:
def func(): print(111) yield 222 print(333) yield 444 print(555) yield 666 gen = func() #这里并没有直接执行这个函数,只是获取了这个函数生成器, for i in gen: #在循环这个函数后,生成器才会执行func()这个函数。i才会找gen要值,func才会执行 print(i) 结果: 111 222 333 444 555 666
三:列表推导式:
例如: lst = [] for i in range(1, 15): lst.append(i) print(lst) 这个代码块是,给出一个列表,通过循环,将数字添加到新的列表中去
001):可以用列表推导式:
lst = [i for i in range(1, 15)] print(lst) 列表是常用写法: [ 结果 for 变量 in 可迭代对象]
002):列表推导式还可以用来筛选
获取1-100内所有的偶数 lst = [i for i in range(1, 100) if i % 2 == 0] print(lst)
四:生成器和列表推导式的区别:
生成器: 有yield的函数体 列表推导式:( [ 结果 for 变量 in 可迭代对象] ) 列表推导式是通过一行来构建我们需要的列表,列表推导式看起来代码简单。但是出了 错误很难排查!
五:生成器表达式:
001):⽣成器表达式和列表推导式的语法基本上是⼀样的. 只是把[]替换成()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
gen = (i for i in range(10)) print(gen) 结果: <generator object <genexpr> at 0x106768f10> 打印的结果就是⼀个⽣成器. 我们可以使⽤for循环来循环这个⽣成器: gen = ("麻花藤我第%s次爱你" % i for i in range(10)) for i in gen: print(i)
六:⽣成器表达式和列表推导式的区别:
1. 列表推导式比较耗内存. ⼀次性加载. ⽣成器表达式⼏乎不占⽤内存. 使⽤的时候才分
配和使⽤内存
2. 得到的值不⼀样. 列表推导式得到的是⼀个列表. ⽣成器表达式获取的是⼀个⽣成器.
举个栗⼦.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
同样⼀篮⼦鸡蛋. 列表推导式: 直接拿到⼀篮⼦鸡蛋. ⽣成器表达式: 拿到⼀个老⺟鸡. 需要
鸡蛋就给你下鸡蛋.
⽣成器的惰性机制: ⽣成器只有在访问的时候才取值. 说⽩了. 你找他要他才给你值. 不找他
要. 他是不会执⾏的.
七:总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式
⽣成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选) ⽣成器表达式可以直接获取到⽣成器对象. ⽣成器对象可以直接进⾏for循环. ⽣成器具有 惰性机制.