python 生成器 + 生成器函数 + 推导表达式 + 生成器表达式
View Code
生成器
生成器的本质其实就是迭代器
生成器的特点和迭代器一样:
取值方式和迭代器一样( __next__(), send() 可以给上一个yield传值 )
生成器一般是由生成器函数或者生成器表达式来创建
其实就是手写的迭代器
生成器函数
yield 和 return 一样可以返回值
和普通函数没有区别. 里面有yield 的函数就是生成器函数.
生成器函数最后收尾的是yield,否则会报错 StopIterration
1 def func(): 2 print("娃哈哈") 3 yield 1 # return和yield都可以返回数据 4 print("呵呵呵") 5 gen = func() # 不会执行这个函数. 获取的是生成器
函数中如果有yield 这个函数就是生成器函数. 生成器函数() 获取的是生成器. 这个时候不执行函数
yield: 相当于return 可以返回数据. 但是yield不会彻底中断函数. 分段执行函数.
gen.__next__() 执行函数. 执行到下一个yield.
gen.__next__() 继续执行函数到下一个yield.
1 # 普通函数 2 def order(): 3 lst = [] 4 for i in range(100): 5 lst.append("衣服"+str(i)) 6 return lst 7 ll = order() 8 print(ll)
9 # 生成器函数 10 def order(): 11 for i in range(100): 12 yield "衣服"+str(i) 13 g = order() # 获取生成器 14 f = g.__next__() #仅执行一次 遇到yield停止 15 print(f) 16 ret = g.__next__() 17 print(ret) 18 #衣服0 19 #衣服1
__next__( ) : 执行到下一个yield, 分段执行函数
send( ) : 执行到下一个yield, 并给上一个yield传值. 必须有参数.
不能在开头(没有上一个yield), 最后一个yield也不可以用send()传值
def func(): print("我是第一个段") a = yield 123 #第一次执行到 yield 123 但是并没有赋值给a print(a) print("石可心是第二段") b = yield 456 print(b) print("刘伟是最后一个段") yield 79 # 最后收尾一定是yield g = func() #获取生成器, 不执行函数 print(g.__next__()) # 没有上一个yield 所以不能使用send() 开头必须是__next__() print(g.send("煎饼果子")) print(g.send("韭菜盒子")) # 我是第一个段 # 123 # 煎饼果子 # 石可心是第二段 # 456 # 韭菜盒子 # 刘伟是最后一个段 # 79
练习:
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) # 我吃什么啊 # 馒头 # a= 胡辣汤 # 鸡蛋灌饼 # b= 狗粮 # 韭菜盒子 # c= 猫粮 # GAME OVER
for 循环 和 list( ) 中自带__next__(), 因此会执行生成器函数.
def func(): yield 1 yield 13 yield 26 gen = func() #仅获取生成器, 不执行函数 for i in func(): # for的内部一定有__next__(), 因此执行函数 print(i) print(list(func())) # 内部都有__next__(), 也会执行函数 # 1 # 13 # 26 # [1, 13, 26]
推导式 (列表 字典 集合)
普通生成列表用for 循环
lst=[] for i in range(1,5): lst.append('python'+str(i)) print(lst) # ['python1', 'python2', 'python3', 'python4']
1) 列表推导式 : [结果 for 循环 条件筛选] 一句话生成列表
lst = ["python"+str(j) for j in range(1,5)] print(lst) # ['python1', 'python2', 'python3', 'python4'] # 求奇数列表 lst = [i for i in range(20) if i%2==1] print(lst) #[1, 3, 5, 7, 9, 11, 13, 15, 17, 19] # 100以内能被3整除的数的平方 lst = [i*i for i in range(20) if i%3==0] print(lst) #[0, 9, 36, 81, 144, 225, 324] # 寻找名字中带有两个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) #['Jefferson', 'Wesley', 'Steven', 'Jennifer']
2) 字典推导式 : {k:v for 循环 条件筛选}
# [11,22,33,44] ==>> {0:11,1:22} 列表转为字典,只要前两个 lst = [11,22,33,44] dic = {i:lst[i] for i in range(len(lst)) if i < 2} # 字典推导式就一行 print(dic) #{0: 11, 1: 22} dic = {"jj": "林俊杰", "jay": "周杰伦", "zs": "赵四", "ln":"刘能"} d = {v : k for k,v in dic.items()} #k,v 互换 print(d) # {'林俊杰': 'jj', '周杰伦': 'jay', '赵四': 'zs', '刘能': 'ln'}
3) 集合推导式 : {k for 循环 条件筛选}
可用于去重
s = {i for i in range(100)}
print(s)
lst = [1, 1, 4, 6,7,4,2,2]
s = { el for el in lst } # 可去除重复
print(s)
s = set(lst) #等价于
print(s)
生成器表达式
特点 :
1. 惰性机制
2. 只能向前
3. 节省内存
语法 : (结果 for 循环 条件筛选) 外面是小括号
# 生成器表达式 (元组) tu = (i for i in range(10)) #没有元组推导式, print(tu) #是个生成器 #<generator object <genexpr> at 0x000002A4A48D0E60> print(tu.__next__()) # 0 print(tu.__next__()) # 1 print(tu.__next__()) # 2
def func(): print(111) yield 222 yield 333 g = func() # 获取生成器 g1 = (i for i in g) # 生成器 g2 = (i for i in g1) # 生成器 print(list(g)) # 为[222,333] 源头. 从源头把数据拿走了 print(list(g1)) # 为[] 这里执行的时候. 源头已经没有数据 print(list(g2)) # 为[] 这里也没有值了 # 111 # [222, 333] # [] # []
重点分析:
def add(a,b): return a+b def test(): for i in range(4): yield i g = test() #获取生成器 # 以下拆开部分等价于for 循环中的部分 # n = 1 # g = (add(n, i) for i in g) #只是生成器没有拿值 # n = 10 # g = (add(n, i) for i in g) #只是生成器没有拿值 # n = 5 # g = (add(n, i) for i in g) #只是生成器没有拿值 for n in [1,10,5]: #循环3次 最后一次的 g = (add(n,i) for i in g) #等价于: g = (add(n,i) for i in (add(n,i) for i in (add(n,i) for i in g))) print(list(g)) #这时候才取值, 循环3次,最后一次n取值为5, 前两次循环也带入5计算 print(list(g)) #为[] 因为前面的list取完了,g中即test()源头中没有数据了 # [15, 16, 17, 18] # []
g=test() for n in [1,10,5]: #循环3次 最后一次的 g = (add(n,i) for i in g) print(list(g)) #等于 1 的时候取值,取完了后面的都为空 # [1, 2, 3, 4] # [] # []

浙公网安备 33010602011771号