Использование сопрограммы в качестве декоратора

в этом случае:

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