Day 15 python 学习笔记:list(g),g.send(),列表推导式,生成器表达式
Part 1: list
我们知道了含有 yield 的函数就是生成器。里面的值是只能被顺序取用一次,取完就没有了。
生成器里面的值在用的时候才取。
补充:list可以把生成器里的值全部取走后强转成列表的数据类型。list就好比是一个催债的。。。
1 def func(): 2 yield 1 3 yield 2 4 yield 3 5 6 g = func() 7 for i in g: 8 print(i) # 1,2,3 9 print(list(g)) #[]
然而,这里需要注意的是:上方的一个for循环已经把生成器内的值全部都取走了。此时再用list强掳,结果只能是灰飞烟灭。
Part 2: send
例1:
1 def average_func(): 2 '''求平均值''' 3 total = 0 4 count = 0 5 average = 0 6 while True: 7 value = yield average #0 30.0 25.0 8 total += value #30 50 9 count += 1 #1 2 10 average = total/count #30 25 11 g = average_func() 12 print(g.send(30)) # send()里的值传给value 13 print(g.__next__()) #激活生成器 14 print(g.send(30)) 15 print(g.send(20)) 16 print(g.send(10))
首先:send和next工作的起止位置是完全相同的
send可以把一个值作为信号量传递到函数中去
在生成器执行伊始,只能先用next
只要用send传递参数的时候,必须在生成器中还有一个未被返回的yield
例2:
有一天,金角大王和银角大王肚子饿了,想要吃包子,来找我要包子吃。不过这两个吃货的胃口实在太大,咱做吃包子的速度哪跟得上她们俩吃得快?为了避免这俩哥们儿“由一只包子引发的血案”,于是就和他们商量好了,我做一个包子,你们俩分着吃,等我做完第2个包子,你们俩再分着吃,一共就做10个包子,管你们能吃饱!于是我写了一个函数:
1 import time 2 def consumer(name): 3 print("%s准备吃包子啦!"%name) 4 while True: 5 baozi = yield 6 print("包子%s来了,被%s吃了!"%(baozi+1,name)) 7 8 def producter(name): 9 c1 = consumer("Alex") 10 c2 = consumer("Wutenglan") 11 c1.__next__() 12 time.sleep(1) 13 c2.__next__() 14 time.sleep(1) 15 print("老子准备做包子啦!") 16 for i in range(10): 17 time.sleep(1) 18 print("老子做了1个包子,被分成了两半!") 19 time.sleep(1) 20 c1.send(i) 21 time.sleep(1) 22 c2.send(i) 23 producter("xinhao") 24 print("包子统统吃完了!")
有一种两段函数交替运行的感觉,据说这种叫携程。啊呸!叫协程。。。
例3:
1 def func(): 2 print(1) 3 yield 2 4 print(3) 5 value = yield 4 6 print(5) 7 yield value 8 9 g = func() #g是生成器 10 print(g.__next__()) #调用生成器g, 打印1,返回2 11 print(g.send(88)) #send的值没有变量接收,等价于执行了一次__next__();打印3返回4 12 print(g.__next__()) #打印5,返回None(注意:此处并没有给value传值) 13 14 #运行结果为: 15 1 16 2 17 3 18 4 19 5 20 None
Part 3: 列表推导式
例1:
1 new_l = [] 2 for i in [1,3,5]: 3 new_l.append(i*i) 4 print(new_l) 5 6 # 等价于一句话: 7
print([i*i for i in [1,3,5]]) # 结果必须是一个列表
例2:30以内所有能被3整除的数的平方
1 def squared(x): 2 return x*x 3 4 multiples = [squared(i) for i in range(30) if i % 3 is 0] # 列表推导式还可以调用函数 5 print(multiples)
Part 4: 字典推导式
例1:将一个字典的key和value对调
1 mcase = {'a': 10, 'b': 34} 2 mcase_frequency = {mcase[k]: k for k in mcase} 3 print(mcase_frequency)
例2:将大小写对应的value值相加,将k统一成小写
1 mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} 2 mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()} #get(key,0),若取不到则值为0 3 print(mcase_frequency)
例3:求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表
1 print([(x,y) for x in range(5) if x%2==0 for y in range(5) if y %2==1])
例4:求M中3,6,9组成的列表 M = [[1,2,3],[4,5,6],[7,8,9]]
1 print([row[2] for row in M])
Part 5: 集合推导式
计算列表中每个值的平方,自带去重功能
1 squared = {x**2 for x in [1, -1, 2]} 2 print(squared) 3 # Output: set([1, 4])
以上,都不重要。。。能看懂就可以了。
Part 6: 生成器表达式
生成器表达式就是把列表表达式的[],替换成()就可以了,其他都一样。
虽然只是一个符号的差别,可是工作原理却大不相同。
列表推导式[] - 生成器表达式()
尽量让推导式简化你的操作,增强代码的可读性
如果推导式过于复杂了,应该转换成普通的python代码
所有的列表推导式都可以转换成生成器表达式,并且应该在代码中尽可能多使用生成器表达式而不是列表推导式
在代码里 多层嵌套的for循环是禁忌 —— 会大幅度增加代码的复杂度
Part 7: 生成器表达式挖坑填坑
1 def demo(): 2 for i in range(4): 3 yield i 4 5 g=demo() 6 7 g1=(i for i in g) 8 g2=(i for i in g1) # 此处等价于 g2=(i for i in g) 9 10 print(list(g1)) #[0,1,2,3] 11 print(list(g2)) #g2问g1要,g1是从g里拿的,g已经被g1拿完了,g只有一个,因此g2啥也拿不到
13 # 运行结果为:
14 [0,1,2,3] 15 []
1 def demo(): 2 for i in range(4): 3 yield i 4 5 g=demo() 6 7 g1=(i for i in g) 8 g2=(i for i in list(g1)) # g2中的list(g1)先被执行,g2有值,g2=(0,1,2,3) 9 10 print(list(g1)) # 由于g1已经被掏空,因此此处已经取不到值了 11 print(list(g2)) 12 13 # 运行结果为: 14 [] 15 [0,1,2,3]
Part 8: 生成器表达式的应用
例1:
1 def add(n,i): 2 return n+i 3 4 def test(): 5 for i in range(4): 6 yield i 7 8 g=test() 9 10 for n in [1,10,5]: 11 g=(add(n,i) for i in g) 12 print(list(g)) 13 14 # 推导过程: 15 # 当 n=1,10,5时,执行 g = (add(n)) 16 # n = 1 17 # g = (add(1,i) for i in g) # 生成一个生成器,不干活 18 # n = 10 19 # g = (add(10,i) for i in (add(10,i) for i in g)) # 生成另一个生成器,也不干活 20 # n = 5 21 # g = (add(5,i) for i (in add(5,i) for i in (add(5,i) for i in g))) # 生成又一个生成器,还是不干活 22 # print(list(g)) # 看见list,开始干活! 23 # =>print(list (add(5,i) for i (in add(5,i) for i in (add(5,i) for i in g)))) 24 # =>print(list (add(5,i) for i (in add(5,i) for i in (add(5,i) for [0,1,2,3])))) 25 # =>print(list (add(5,i) for i (in add(5,i) for [5,6,7,8]))) 26 # =>print(list (add(5,i) for [10,11,12,13])) 27 # =>print(list (15,16,17,18)) 28 29 #运行结果为: 30 [15,16,17,18]
例2:以下代码建议配合视频讲解一起阅读!
1 import os 2 3 def init(func): 4 def wrapper(*args,**kwargs): 5 g=func(*args,**kwargs) 6 next(g) 7 return g 8 return wrapper 9 10 @init 11 def list_files(target): 12 while 1: 13 dir_to_search=yield 14 for top_dir,dir,files in os.walk(dir_to_search): 15 for file in files: 16 target.send(os.path.join(top_dir,file)) 17 @init 18 def opener(target): 19 while 1: 20 file=yield 21 fn=open(file,encoding="utf-8") 22 target.send((file,fn)) 23 @init 24 def cat(target): 25 while 1: 26 file,fn=yield 27 for line in fn: 28 target.send((file,line)) 29 30 @init 31 def grep(pattern,target): 32 while 1: 33 file,line=yield 34 if pattern in line: 35 target.send(file) 36 @init 37 def printer(): 38 while 1: 39 file=yield 40 if file: 41 print(file) 42 43 g=list_files(opener(cat(grep('python',printer())))) 44 45 g.send('/test1')

浙公网安备 33010602011771号