dans ce scénario:
async def foo(f):
async def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
@foo
async def boo(*args, **kwargs):
pass
l'appel à foo comme décorateur pour boo décorateur est-il un appel asynchrone?
--Première édition: comment gérer une chaîne de coroutines en tant que décorateurs?
Merci au commentaire de @ blacknght, considérant
def foo():
def wrapper(func):
@functools.wraps(func)
async def wrapped(*args):
# Some fancy foo stuff
return await func(*args)
return wrapped
return wrapper
et
def boo():
def wrapper(func):
@functools.wraps(func)
async def wrapped(*args):
# Some fancy boo stuff
return await func(*args)
return wrapped
return wrapper
comme deux décorateurs, et
@foo()
@boo()
async def work(*args):
pass
Comme foo
enveloppe la coroutine work
, la clé est de await
la func(*arg)
dans les deux décorateurs.
def foo(f):
async def wrapper(*args, **kwargs):
return await f(*args, **kwargs)
return wrapper
@foo
async def boo(*args, **kwargs):
pass
Votre décorateur doit être une fonction normale et cela fonctionnera bien.
Lorsqu'un décorateur est évalué python exécute la méthode avec la fonction comme argument.
@foo
async def boo():
pass
Évalue à:
__main__.boo = foo(boo)
Si foo est un type de fonction asynchrone (main. Boo) sera un objet coroutine, pas un objet fonction. Mais si foo est une fonction de synchronisation régulière, elle sera évaluée immédiatement et main. Boo sera le wrapper retourné.
Voici une autre approche utilisant la bibliothèque decorator
(c'est-à-dire pip install decorator
première):
import asyncio
import decorator
@decorator.decorator
async def decorate_coro(coro, *args, **kwargs):
try:
res = await coro(*args, **kwargs)
except Exception as e:
print(e)
else:
print(res)
@decorate_coro
async def f():
return 42
@decorate_coro
async def g():
return 1 / 0
async def main():
return await asyncio.gather(f(), g())
if __name__ == '__main__':
asyncio.run(main())
Production:
42
division by zero