使用协同程序作为装饰器

Jug*_*aut 15 python asynchronous python-3.x

在这种情况下:

async def foo(f):
    async def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper

@foo
async def boo(*args, **kwargs):
    pass
Run Code Online (Sandbox Code Playgroud)

是调用foo作为boo装饰器和异步调用的装饰器?

--First Edit:另外如何处理作为装饰器的coroutines调用链?

小智 22

def foo(f):
    async def wrapper(*args, **kwargs):
        return await f(*args, **kwargs)
    return wrapper

@foo
async def boo(*args, **kwargs):
    pass
Run Code Online (Sandbox Code Playgroud)

你的装饰器需要是一个正常的功能,它会正常工作。

当一个装饰器被评估时,python 以函数作为参数执行该方法。

@foo
async def boo():
    pass
Run Code Online (Sandbox Code Playgroud)

评估为:

__main__.boo = foo(boo)
Run Code Online (Sandbox Code Playgroud)

如果 foo 是一个异步函数类型(main .boo )将是一个协程对象,而不是一个函数对象。但是如果 foo 是一个常规的同步函数,它会立即求值并且main .boo 将是返回的包装器。


Jug*_*aut 20

感谢@ blacknght的评论,考虑一下

def foo():
    def wrapper(func):
        @functools.wraps(func)
        async def wrapped(*args):
             # Some fancy foo stuff
            return await func(*args)
        return wrapped
    return wrapper
Run Code Online (Sandbox Code Playgroud)

def boo():
    def wrapper(func):
        @functools.wraps(func)
        async def wrapped(*args):
            # Some fancy boo stuff
            return await func(*args)
        return wrapped
    return wrapper
Run Code Online (Sandbox Code Playgroud)

作为两个装饰者,和

@foo()
@boo()
async def work(*args):
    pass
Run Code Online (Sandbox Code Playgroud)

由于foo被包装的work协程,关键是要awaitfunc(*arg)两个装饰.

  • 不错的解决方案!我发现你不需要外部`def`。例如,如果您从第一个示例中删除了 `def foo()` 和 `return wrapper`,那么使用 `@wrapper`(无括号)进行装饰将具有相同的效果。 (2认同)
  • 您也不需要在“wrapped”中使用“async”和“await”,除非您操纵返回值。否则,您只需添加一个任务等待另一个任务的开销。不使用“async”还具有能够在正常函数中使用相同装饰器的优点。使用带有单个“return wait”的“async”的唯一优点是清楚地记录必须等待的函数,但这在装饰器包装器中并不重要。 (2认同)
  • 非常感谢,真的很有帮助,您可以向 foo 和 boo 添加参数以在装饰器中传递参数。 (2认同)