Наличие выражения yield
в функции или методе, определенных с помощью async def
, дополнительно определяет функцию как функцию асинхронного генератора
Когда вызывается функция асинхронного генератора, она возвращает асинхронный итератор, известный как объект асинхронного генератора. Затем этот объект управляет выполнением функции генератора. Объект асинхронного генератора обычно используется в инструкции async for/in
в функции сопрограммы аналогично тому, как объект генератора использовался бы в инструкции for/in
.
Вызов одного из методов асинхронного генератора возвращает объект ожидания с помощью await
, а выполнение начинается, когда этот объект ожидается. В это время выполнение переходит к первому выражению yield
, где оно снова приостанавливается, возвращая значение expression_list
ожидающей с помощью await
сопрограмме. Как и в случае с обычным генератором, приостановка означает, что сохраняется все локальное состояние, включая текущие привязки локальных переменных, указатель на инструкцию, внутренний стек вычисления и состояние любой обработки исключений. Когда выполнение возобновляется ожиданием await
следующего объекта, возвращаемого методами асинхронного генератора, функция может выполняться точно так же, как если бы выражение yield
было просто еще одним внешним вызовом. Значение выражения yield
после возобновления зависит от метода, который возобновил выполнение. Если используется agen.__anext__()
, то результатом будет None
. В противном случае, если используется agen.asend()
, результатом будет значение, переданное этому методу.
Если случается, что асинхронный генератор завершает работу раньше break
, то отменяются вызывающая задача или другие исключения, запускается код очистки асинхронного генератора и, возможно, вызывает исключения или обращается к контекстным переменным в неожиданном контексте - возможно, по истечении срока службы задач, это зависит от того, или во время завершения цикла событий, когда вызывается перехват сборки мусора асинхронным генератором. Чтобы предотвратить такое поведение, вызывающий должен явно закрыть асинхронный генератор, вызвав метод agen.aclose()
для завершения работы генератора и, в конечном счете, отсоединить его от цикла событий.
В функции асинхронного генератора выражения yield
разрешены в любом месте конструкции try/except
. Однако, если асинхронный генератор не возобновляется до его завершения (из-за достижения нулевого количества ссылок или из-за сборки мусора), то выражение yield
в конструкции try/except
может привести к сбою в выполнении ожидающих выполнения предложений finally
. В этом случае цикл событий или планировщик, запускающий асинхронный генератор, несет ответственность за вызов метода agen.aclose()
итератора асинхронного генератора и запуск результирующего объекта сопрограммы, что позволяет выполнять любые ожидающие выполнения finally
.
Чтобы позаботиться о завершении цикла событий, цикл событий должен определить функцию финализатора, которая принимает асинхронный генератор-итератор и предположительно вызывает agen.aclose()
и выполняет сопрограмму. Этот финализатор может быть зарегистрирован путем вызова sys.set_asyncgen_hooks()
. При первой итерации асинхронный генератор-итератор сохранит зарегистрированный финализатор, который будет вызван после завершения.
Выражение
yield from <expr>
, при использовании в функции асинхронного генератора - является синтаксической ошибкой.
Ниже описаны методы асинхронного генератора, которые используются для управления выполнением функции генератора.
Примечание:
awaitable
- это объект, который можно использовать в выражении wait
. Может быть сопрограммой или объектом с методом __await__()
.agen.__anext__()
:Метод agen.__anext__()
возвращает объект awaitable
, который запускает выполнение асинхронного генератора или возобновляет его с последнего выполненного выражения yield
. При возобновлении работы асинхронный генератор будет продолжен до следующего выражения yield
, при этом в возвращаемом состоянии ожидания текущее выражение yield
всегда оценивается как None
. Значением expression_list
выражения yield
является значение исключения StopIteration
, вызванное завершением сопрограммы. Если асинхронный генератор завершает работу без получения какого либо значения, то awaitable
вызывает исключение StopAsyncIteration
, сигнализирующее о завершении асинхронной итерации.
Этот метод обычно вызывается неявно асинхронным циклом for.
Проще говоря agen.__anext__()
выполняет одну итерацию асинхронного генератора, возвращает объект awaitable
, который использует исключение StopItered
для "выдачи" значений и исключение StopAsyncItered
для оповещения об окончании итерации. Асинхронные генераторы определяют оба этих метода.
async def genfunc(): yield 1 yield 2 gen = genfunc() assert gen.__aiter__() is gen assert await gen.__anext__() == 1 assert await gen.__anext__() == 2 await gen.__anext__() # Эта строка будет вызывать StopAsyncIteration.
agen.asend(value)
:Метод agen.asend()
возвращает объект awaitable
, который при запуске возобновляет выполнение асинхронного генератора. Как и в случае метода send()
для обычного генератора, он "отправляет" значение value
в асинхронный генератор и аргумент value
становится результатом текущего выражения yield
.
awaitable
, возвращаемый методом asend()
, вернет значение исключения StopIteration
или поднимет исключение StopAsyncIteration
. asend()
вызывается для запуска асинхронного генератора, то он должен вызываться с None
в качестве аргумента, потому что нет выражения yield
, которое могло бы получить значение.async def gen(): await asyncio.sleep(0.1) v = yield 42 print(v) await asyncio.sleep(0.2) g = gen() await g.asend(None) # Вернет 42 после сна в течение 0,1 секунды. await g.asend('hello') # Напечатает 'hello' и поднимет StopAsyncIteration # после сна в течение 0,2 секунд.
agen.athrow(value)
agen.athrow(type[, value[, traceback]])
:Изменено в Python 3.12: Вторая сигнатура
agen.athrow(type[, value[, traceback]])
устарела и может быть удалена в будущей версии Python.
Метод agen.athrow()
возвращает объект awaitable
, который вызывает исключение типа type
в точке, где асинхронный генератор был приостановлен и возвращает исключение StopIteration
.
awaitable
вызывает исключение StopAsyncItered
. awaitable
, это исключение распространяется на объект вызвавший awaitable
.async def gen(): try: await asyncio.sleep(0.1) yield 'hello' except ZeroDivisionError: await asyncio.sleep(0.2) yield 'world' g = gen() v = await g.asend(None) print(v) # Напечатает 'hello' после сна 0.1 секунды. v = await g.athrow(ZeroDivisionError) print(v) # Напечатает 'world' после сна 0.2 секунды.
agen.aclose()
:Метод agen.aclose()
возвращает значение awaitable
, которое при запуске выдает исключение GeneratorExit
в асинхронный генератор в точке, где он был приостановлен.
GeneratorExit
не перехватывая исключение, то возвращенный awaitable
вызовет исключение StopIteration
. Любые дальнейшие значение awaitable
последующих вызовов асинхронного генератора, вызовут исключение StopAsyncIteration
. awaitable
вызывает исключение RuntimeError
. awaitable
. aclose()
вернут объект awaitable
, который ничего не делает.Метод agen.aclose()
очень похож на то, что метод close() делает с обычными генераторами Python, за исключением того, что для выполнения aclose()
требуется цикл обработки событий.