Вирази дохідності

Оновлено: 24.04.2023

yield_atom       ::=  "(" yield_expression ")"
yield_expression ::=  "yield" [expression_list | "from" expression]

Вираз yield використовується під час визначення функції generator або функції asynchronous generator і тому може використовуватися лише в тілі визначення функції. Використання виразу yield у тілі функції робить цю функцію функцією-генератором, а використання його в тілі функції async def призводить до того, що функція співпрограми стає асинхронною функцією-генератором. Наприклад:

def gen():  # defines a generator function
    yield 123

async def agen(): # defines an asynchronous generator function
    yield 123

Через їхній побічний вплив на область, що містить, вирази yield не дозволені як частина неявно визначених областей, які використовуються для реалізації розуміння та виразів генератора.

Функції генератора описані нижче, тоді як функції асинхронного генератора описані окремо в розділі Функції асинхронного генератора.

When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of the generator function. The execution starts when one of the generator’s methods is called. At that time, the execution proceeds to the first yield expression, where it is suspended again, returning the value of expression_list to the generator’s caller, or None if expression_list is omitted. By suspended, we mean that all local state is retained, including the current bindings of local variables, the instruction pointer, the internal evaluation stack, and the state of any exception handling. When the execution is resumed by calling one of the generator’s methods, the function can proceed exactly as if the yield expression were just another external call. The value of the yield expression after resuming depends on the method which resumed the execution. If __next__() is used (typically via either a for or the next() builtin) then the result is None. Otherwise, if send() is used, then the result will be the value passed in to that method.

Усе це робить функції генератора досить схожими на співпрограми; вони поступаються кілька разів, вони мають більше однієї точки входу, і їхнє виконання може бути призупинено. Єдина відмінність полягає в тому, що функція-генератор не може контролювати, де має продовжуватися виконання після того, як вона виходить; керування завжди передається абоненту генератора.

Вирази yield дозволені будь-де в конструкції try. Якщо генератор не відновлено до його завершення (досягнувши нульової кількості посилань або збираючи сміття), буде викликано метод close() генератора-ітератора, дозволяючи будь-які очікуючі finally пропозиції для виконання.

Коли використовується yield from , наданий вираз має бути повторюваним. Значення, отримані шляхом ітерації цього ітерованого, передаються безпосередньо до виклику методів поточного генератора. Будь-які значення, передані за допомогою send(), і будь-які винятки, передані за допомогою throw(), передаються базовому ітератору, якщо він має відповідні методи. Якщо це не так, то send() викличе AttributeError або TypeError, а throw() просто викличе переданий виняток негайно.

Коли основний ітератор завершено, атрибут value піднятого екземпляра StopIteration стає значенням виразу yield. Його можна встановити явно під час виклику StopIteration або автоматично, коли субітератор є генератором (шляхом повернення значення з субгенератора).

Дужки можуть бути опущені, якщо вираз yield є єдиним виразом у правій частині оператора призначення.

>>> def echo(value=None):
...     print("Execution starts when 'next()' is called for the first time.")
...     try:
...         while True:
...             try:
...                 value = (yield value)
...             except Exception as e:
...                 value = e
...     finally:
...         print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> print(next(generator))
Execution starts when 'next()' is called for the first time.
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam',)
>>> generator.close()
Don't forget to clean up when 'close()' is called.