在Python中装饰生成器:在yield之间调用一些方法

时间:2018-08-30 22:25:46

标签: python generator decorator

我发现了一些有关使用yield from在Python here中修饰生成器函数的非常有用的信息。例如:

def mydec(func):
    def wrapper(*args, **kwargs):
        print(f'Getting values from "{func.__name__}"...')
        x = yield from func(*args, **kwargs)
        print(f'Got value {x}')
        return x
    return wrapper

@mydec
def mygen(n):
    for i in range(n):
        yield i

但是,这似乎仅允许在生成器生命周期的开始和结束时添加修饰行为:

>>> foo = mygen(3)
>>> x = next(foo)
Getting values from "mygen"...
>>> x
0
>>> x = next(foo)
>>> x
1
>>> x = next(foo)
>>> x
2
>>> x = next(foo)
Got value None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> x
2

但是,我有兴趣在每次生成器产生时使用装饰器来实现某些行为。但是,装饰器不应修改从生成器获取的值。也就是说,例如,我想要输出:

>>> foo = mygen(3)
>>> x = next(foo)
Getting values from "mygen"...
Got value 0
>>> x
0
>>> x = next(foo)
Got value 1
>>> x
1
>>> x = next(foo)
Got value 2
>>> x
2

因此,每个收益率都会调用print,但是收益率值保持不变。

这可能吗?

1 个答案:

答案 0 :(得分:3)

yield from用于协同程序。你不是在做协程的东西。只是迭代生成器:

def mydec(func):
    def wrapper(*args, **kwargs):
        print(f'Getting values from "{func.__name__}"...')
        gen = func(*args, **kwargs)
        for value in gen:
            print(f'got value {value}')
            yield value
    return wrapper