Python进阶-VI 生成器函数进阶、生成器表达式、推导式

一、生成器函数进阶

需求:求取移动平均数
1、应用场景之一,在奥运会气枪射击比赛中,每打完一发都会显示平均环数!
 1 def show_avg():
 2     print('你已进入显示移动平均环数系统!')
 3     a = yield
 4     avg = a/1
 5     b = yield
 6     avg = (a + b)/2
 7     print('目前的平均环数是:')
 8     yield avg
 9 
10 generator = show_avg()
11 generator.__next__()
12 print(generator.send(10))  # 第一发打了10环
13 print(generator.send(9.8))  # 第二发打了9.8环
send 获取下一个值的效果和next基本一致,
只是在获取下一个值的时候,给上一yield的位置传递一个数据
使用send的注意事项
# 第一次使用生成器的时候 是用next获取下一个值
# 最后一个yield不能接受外部的值

2、获取移动平均值,数据如下:10,20,30,40
 1 # 进阶一下:用循环取平均值
 2 def average():
 3     sum = 0
 4     count = 0
 5     avg = 0
 6     while 1:
 7         num = yield avg
 8         sum += num
 9         count += 1
10         avg = sum/count
11 g = average()
12 print(g.__next__())   #执行该语句,代码就执行到:= yield avg 返回的avg = 0 其他参数的值也都是默认的
13 print(g.send(10))     #执行该语句,代码进入到第二次循环,yield avg 返回avg = 10,接着num = 10,sum = 10,count = 1,avg = 10
14 print(g.send(20))     #执行该语句,代码进入到第三次循环,yield avg 返回avg = 15,接着num = 20,sum = 10+20,count = 1+1,avg =(10+20)/2
15 print(g.send(30))     #执行该语句,代码进入到第四次循环,yield avg 返回avg = 20,接着num = 30,sum = 10+20+30,count = 1+1+1,avg =(10+20+30)/3
16 print(g.send(40))     #执行该语句,代码进入到第五次循环,yield avg 返回avg = 25,接着num = 40,sum = 10+20+30+40,count = 1+1+1+1,avg =(10+20+30+40)/4

3、预激生成器的装饰器
 1 #send前必须要__next__()一下,如果大量的使用到,可以考虑使用装饰器来做!
 2 # 我们来改造一下打靶环数的例子:
 3 def next(func):
 4     def inner(*args,**kwargs):
 5         g = func(*args,**kwargs)
 6         g.__next__()
 7         return g
 8     return inner
 9 
10 @next
11 def avg_ring_count():
12     print('你已进入显示移动平均环数系统!')
13     sum = 0
14     count = 0
15     avg = 0
16     while 1:
17         print('目前的平均环数是:')
18         num = yield avg
19         sum += num
20         count += 1
21         avg = sum / count
22 
23 g = avg_ring_count()
24 print(g.send(10))
25 print(g.send(9.8))
26 print(g.send(9.6))
27 print(g.send(8.9))

 

二、生成器表达式和各种推导式

1、引入的例子:列表推导式
love_list = []
for i in range(200):
    love_list.append('ILOVEU%d'%i)
#  可以写成:
love_list = ['ILOVEU%d'%i for i in range(200)]
 2、引入生成器表达式
#将上面的列表推导式,小改一下即可:
generator = ('ILOVEU%d'%i for i in range(20))

for i in generator:
    print(i)
 我们发现两者的不同之处在于:
括号不一样
返回的值不一样 === 几乎不占用内存,你要一条就给一条,而不是一次性都拿出来
3、各种推导式
  1)列表推导式,上面已经介绍过了
 1 #30以内所有能被3整除的数
 2 ret = [i for i in range(30) if i%3 == 0]  #完整的列表推导式
 3 g = (i for i in range(30) if i%3 == 0)  #完整的列表推导式
 4 print(ret)
 5 
 6 #30以内所有能被3整除的数的平方
 7 ret = [i*i for i in (1,2,3,4) if i%3 == 0]
 8 ret = (i*i for i in range(30) if i%3 == 0)
 9 print(ret)
10 
11 # 例三:找到嵌套列表中名字含有两个‘e’的所有名字
12 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
13          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
14 ret = [name for lst in names for name in lst if name.count('e') ==2]
15 ret = (name for lst in names for name in lst if name.count('e') ==2)
16 print(ret)
2)字典推导式
 1 #例一:将一个字典的key和value对调
 2 mcase = {'a': 10, 'b': 34}
 3 #{10:'a' , 34:'b'}
 4 mcase_frequency = {mcase[k]: k for k in mcase}
 5 print(mcase_frequency)
 6 
 7 #例二:合并大小写对应的value值,将k统一成小写
 8 mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
 9 #{'a':10+7,'b':34,'z':3}
10 mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase}
11 print(mcase_frequency)
 3)集合推导式
#       自带结果去重功能
squared = {x**2 for x in [1, -1, 2]}
print(squared)

4、各种推导式的小结:

[or{or(每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型)or}or] #遍历之后挨个处理 元素个数不变
[or{or(满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件)or}or] #筛选功能 带if 元素个数可能改变
posted @ 2019-11-29 10:57  四方游览  阅读(203)  评论(0)    收藏  举报