Использование сопрограммы в качестве декоратора
в этом случае:
async def foo(f):
async def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
@foo
async def boo(*args, **kwargs):
pass
является вызовом foo в качестве декоратора для декодера boo асинхронного вызова?
- Первое редактирование:
Также как обрабатывать вызывающую цепочку сопрограмм в качестве декораторов?
Ответы
Ответ 1
Благодаря комментарию @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
и
def boo():
def wrapper(func):
@functools.wraps(func)
async def wrapped(*args):
# Some fancy boo stuff
return await func(*args)
return wrapped
return wrapper
в качестве двух декораторов и
@foo()
@boo()
async def work(*args):
pass
Когда foo
обертывает сопрограмму work
, ключ находится в await
func(*arg)
в обоих декораторах.
Ответ 2
def foo(f):
async def wrapper(*args, **kwargs):
return await f(*args, **kwargs)
return wrapper
@foo
async def boo(*args, **kwargs):
pass
Ваш декоратор должен быть нормальной функцией, и он будет работать нормально.
Когда декоратор оценивается, python выполняет метод с функцией в качестве аргумента.
@foo
async def boo():
pass
Оценивает:
__main__.boo = foo(boo)
Если foo является типом асинхронной функции (main.boo), это будет объект сопрограммы, а не объект функции. Но если foo - обычная функция синхронизации, она сразу же вычислится, и main.boo будет возвращена оболочка.
Ответ 3
Вот альтернативный подход с использованием библиотеки decorator
(т.е. сначала pip install decorator
):
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())
Выход:
42
division by zero