web-dev-qa-db-ja.com

デコレーターとしてコルーチンを使用する

このシナリオでは:

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

@foo
async def boo(*args, **kwargs):
    pass

booデコレータのデコレータとしてのfooの呼び出しは非同期呼び出しですか?

-最初の編集:また、デコレータとしてコルーチンの呼び出しチェーンをどのように処理しますか?

18
Juggernaut

@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
_

2つのデコレータとして

_@foo()
@boo()
async def work(*args):
    pass
_

fooworkコルーチンをラップしているため、両方のデコレータでawaitfunc(*arg)を使用することが重要です。

26
Juggernaut
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が非同期関数の場合、type(main。boo)は関数オブジェクトではなくコルーチンオブジェクトになります。しかし、fooが通常の同期関数である場合は、すぐに評価され、main。booが返されるラッパーになります。

6
user11919393

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
1
Kevin Lyons