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')

 

posted @ 2017-09-05 19:12  折翼的壕哥  阅读(306)  评论(0)    收藏  举报