移动平均值
假如我们有一个需求,需要计算输入数的平均值,以往都是输入的数字是固定的直接求和除以个数即可,现在输入一个数字,平均值就得更新一次,应该怎么处理呢?
我们需要用到生成器,而且需要用到之前提到的send()方法需要传值,然后yield返回 avg:
def generator(): sum=0 count=0 avg=0 while True: num=yield avg sum+=num count+=1 avg=sum/count g=generator() g.__next__() print(g.send(10)) print(g.send(20)) print(g.send(30)) print(g.send(40)) print(g.send(50)) print(g.send(60))
说一下代码的执行流程:
首先generator()函数是一个生成器函数,该函数被调用返回一个生成器给g,首先g.__next__()会先执行到yield avg停止,但是g.__next__()并没有接受返回值,然后执行g.send(10)就是从第一个yield的位置开始,把10赋值给num,然后往下执行,计算均值,然后执行下一个循环,第一句遇到yield avg 把sum=10,count=1计算的返回值avg=10 传给了g.send(10)这里,print()打印出来,后续就重复进行上述传num ,计算avg,yield停止并把avg传给g.send()等
其实我们还可以使调用函数的人更简洁,就是只需要调用g.send(10)传值就可以直接计算每次生成的均值,也就是没有最开始那个g.__next__()函数初试刺激一下生成器函数内部了:
def init(f): def inner(*args,**kwargs): g=f(*args,**kwargs) g.__next__() return g return inner @init def generator(): sum=0 count=0 avg=0 while True: num=yield avg sum+=num count+=1 avg=sum/count g=generator() print(g.send(10)) print(g.send(20)) print(g.send(30)) print(g.send(40)) print(g.send(50))
运行结果:
装饰器的功能就是替代了g.__next__()这一句而已,使得调用者看似不需要写这一句,直接g.send(10)就可以得到每次更新的均值啦!!
还需要说一点,就是装饰器内部,inner()这个闭包函数里面的代码就是跟外部怎么使用func函数是一样的,该返回值就返回值,该返回一个生成器就返回一个生成器~
yield from
如果我们需要挨个打印某个可迭代对象的值,使用生成器,可以这样操作:
def generator(): a='jkldf;df' b='sjkdlfkld' for i in a: yield i for i in b: yield i g=generator() for i in g: print(i)
运行结果:
其实还可以更简单:
def generator(): a='jdskfkldfk' b='sjkdfl' yield from a yield from b g=generator() for i in g: print(i)