python-3.x 使用协程作为装饰器

c8ib6hqw  于 2023-06-25  发布在  Python
关注(0)|答案(4)|浏览(139)

在这种情况下:

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

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

调用foo作为boo decorator的decorator是异步调用吗?

  • -第一次编辑:另外,如何处理作为装饰器的协程调用链?
6qftjkof

6qftjkof1#

感谢@ blacknight的评论,考虑到

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 Package 了work协程,因此关键是在两个装饰器中awaitfunc(*arg)

3qpi33ja

3qpi33ja2#

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是一个常规的synch函数,它将立即求值,并且main.boo将作为 Package 器返回。

axr492tv

axr492tv3#

下面是一种使用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
e5nqia27

e5nqia274#

async def foo(f):
  def wrapper(*args, **kwargs):
    # wrapper pre-function stuff
    result = await f(*args, **kwargs) # key is to await function's result
    # wrapper post-function stuff
    return result 
  wrapper.__name__ = f.__name__ # for some reason, async wrappers don't do this
  # do it to avoid an error if you use the wrapper on multiple functions
  return wrapper

两个关键的更改是等待你正在 Package 的函数,因为它是一个异步函数,以及更改 Package 函数的名称,这样你的程序就不会试图用相同的方式命名多个函数。

相关问题