Using a coroutine as decorator

前端 未结 3 650
生来不讨喜
生来不讨喜 2021-02-03 23:33

in this scenario:

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

@foo
async def boo(*args, **kwa         


        
相关标签:
3条回答
  • 2021-02-03 23:58

    Here is an alternate approach using the decorator library (i.e. pip install decorator first):

    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())
    

    Output:

    42
    division by zero
    
    0 讨论(0)
  • 2021-02-03 23:59

    Thanks to @blacknght's comment, considering

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

    and

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

    as two decorators, and

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

    As the foo is wrapping the work coroutine, the key is to await the func(*arg) in both decorators.

    0 讨论(0)
  • 2021-02-04 00:00
    def foo(f):
        async def wrapper(*args, **kwargs):
            return await f(*args, **kwargs)
        return wrapper
    
    @foo
    async def boo(*args, **kwargs):
        pass
    

    Your decorator needs to be a normal function and it will work fine.

    When a decorator is evaluated python executes the method with the function as the argument.

    @foo
    async def boo():
        pass
    

    Evaluates to:

    __main__.boo = foo(boo)
    

    If foo is an async function type(main.boo) will be a coroutine object, not a function object. But if foo is a regular synch function it will evaluate right away and main.boo will be the wrapper returned.

    0 讨论(0)
提交回复
热议问题