python学习笔记 day13 生成器进阶(二)

移动平均值

假如我们有一个需求,需要计算输入数的平均值,以往都是输入的数字是固定的直接求和除以个数即可,现在输入一个数字,平均值就得更新一次,应该怎么处理呢?

我们需要用到生成器,而且需要用到之前提到的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)

猜你喜欢

转载自www.cnblogs.com/xuanxuanlove/p/9589017.html