⽣成器和⽣成器表达式
一丶生成器和生成器函数
什么是⽣成器. ⽣成器实质就是迭代器.
在python中有三种⽅式来获取⽣成器:
1. 通过⽣成器函数
2. 通过各种推导式来实现⽣成器
3. 通过数据的转换也可以获取⽣成器
def func(): print("111") return 222 ret = func() print(ret) 结果: 111 222
将return 转换成 yield
def func(): print("111") yield 222 ret = func() print(ret) 结果: <generator object func at 0x10567ff68>
生成器的本质就是迭代器
def func(): print("娃哈哈") yield 1 # return和yield都可以返回数据 print("呵呵呵") gen = func() # 不会执行你的函数. 拿到的是生成器 # 函数中如果有yield 这个函数就是生成器函数. 生成器函数() 获取的是生成器. 这个时候不执行函数 # yield: 相当于return 可以返回数据. 但是yield不会彻底中断函数. 分段执行函数. gen.__next__() #执行函数. 执行到下一个yield. gen.__next__() #继续执行函数到下一个yield.
生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), send(): 给上一个yield传值).
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def order(): 2 lst = [] 3 for i in range(10000): 4 lst.append("衣服"+str(i)) 5 return lst 6 7 ll = order() 8 9 def order(): 10 for i in range(10000): 11 yield "衣服"+str(i) 12 g = order() # 获取生成器 13 mingwei = g.__next__() 14 print(mingwei) 15 zhaoyining = g.__next__() 16 print(zhaoyining)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def func(): 2 print("我是第一个段") 3 a = yield 123 4 print(a) 5 print("石可心是第二段") 6 b = yield 456 7 print(b) # ?? 8 print("赵一宁是第三段") 9 c = yield 789 10 print(c) 11 print("刘伟是最后一个段") 12 yield 79 # 最后收尾一定是yield 13 14 15 16 g = func() 17 print(g.__next__()) # 没有上一个yield 所以不能使用send() 开头必须是__next__() 18 print(g.send("煎饼果子")) 19 print(g.send("韭菜盒子")) 20 print(g.send("锅包肉")) ## ??
生成器一般由生成器函数或者生成器表达式来创建
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def eat(): 2 print("我吃什么啊") 3 a = yield "馒头" 4 print("a=",a) 5 b = yield "鸡蛋灌饼" 6 print("b=",b) 7 c = yield "韭菜盒子" 8 print("c=",c) 9 yield "GAME OVER" 10 gen = eat() # 获取生成器 11 12 ret1 = gen. __next__() 13 print(ret1) # 馒头 14 ret2 = gen.send("胡辣汤") 15 print(ret2) 16 17 ret3 = gen.send("狗粮") 18 print(ret3) 19 ret4 = gen.send( "猫粮") 20 print(ret4)
二丶推导式
1. 列表推导式 [结果 for循环 条件筛选]
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
lst = [] for i in range(1, 16): lst.append("python"+str(i)) print(lst) 推导式: 用一句话来生成一个列表 lst = ["python"+str(j) for j in range(1,16)] print(lst) 语法: [结果 for循环 判断]
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
寻找名字中带有两个e的人的名字 names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' ,'Joe'], [ 'Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 1]] lst = [name for line in names for name in line if type(name) == str and name.count("e") == 2] print(lst) # 100以内能被3整除的数的平方 # lst = [i*i for i in range(100) if i%3==0] # print(lst)
2. 字典推导式 {k:v for循环 条件筛选}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 [11,22,33,44] => {0:11,1:22,2:33} 2 lst = [11,22,33,44] 3 dic = {i:lst[i] for i in range(len(lst)) if i < 2} # 字典推导式就一行 4 print(dic) 5 语法:{k:v for循环 条件筛选} 6 7 dic = {"jj": "林俊杰", "jay": "周杰伦", "zs": "赵四", "ln":"刘能"} 8 d = {v : k for k,v in dic.items()} 9 print(d)
3. 集合推导式 {k for循环 条件}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 s = {i for i in range(100)} # 可去除重复 2 print(s) 3 4 # 集合推导式 5 lst = [1, 1, 4, 6,7,4,2,2] 6 s = { el for el in lst } 7 print(s) 8 9 s = set(lst) 10 print(s)
三丶生成器表达式
(结果 for循环 条件)
特点:
1. 惰性机制
2. 只能向前
3. 节省内存(鸡蛋)
⽣成器表达式和列表推导式的区别:
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同理
深坑==> ⽣成器. 要值得时候才拿值.
总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式
⽣成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)
⽣成器表达式可以直接获取到⽣成器对象. ⽣成器对象可以直接进⾏for循环.
def add(a, b): return a + b def test(): for r_i in range(4): yield r_i g = test() for n in [2, 10]: g = (add(n, i) for i in g) print(list(g))
惰性机制 不到最后不会拿值