Вы можете в основном использовать тот же механизм, который используется другим ответом, но применяется к сопрограммам.Например:
def say_hello(function):
def decorated(*args, **kwargs):
function_instance = function(*args, **kwargs)
if isinstance(function_instance, types.AsyncGeneratorType):
async def inner():
print("Hello async generator!")
async for v in function_instance:
yield v
else:
async def inner():
print("Hello coroutine!")
return await function_instance
return inner()
return decorated
Обратите внимание, что в этом случае decorated
определяется с использованием def
вместо async def
.Это гарантирует, что при вызове он сразу начинает работать и может выбирать, что возвращать, асинхронный генератор-итератор для объекта сопрограммы.Поскольку decorated
возвращает объект, созданный путем вызова функции, определенной с async def inner
, функционально он эквивалентен самому async def
.
Ваша test
функция неверна, поскольку онаиспользует for
для перебора асинхронного генератора, и он перебирает сопрограмму.Вместо этого он должен быть async def
и использовать async for
для перебора асинхронного генератора и await
для ожидания сопрограммы.Я использовал следующий код для проверки (generator
и coroutine
не изменились):
async def test():
async for v in generator():
print(v)
await coroutine()
asyncio.run(test())
# or, on Python 3.6 and older:
#asyncio.get_event_loop().run_until_complete(test())