Что делает конструкция yield from в Python и в чем ее польза

Ответ

yield from <iterable> — это синтаксическая конструкция, которая позволяет одному генератору делегировать часть своих операций другому генератору или любому итерируемому объекту. Она напрямую передает управление и значения между вызывающим кодом и вложенным генератором (подгенератором).

Проблема, которую решает yield from: Без этой конструкции для итерации по вложенному генератору пришлось бы писать громоздкий цикл.

# Без yield from
def chain_iterables(iter1, iter2):
    for value in iter1:
        yield value
    for value in iter2:
        yield value

print(list(chain_iterables(range(3), "ABC")))
# Вывод: [0, 1, 2, 'A', 'B', 'C']

Решение с yield from: Код становится значительно чище и декларативнее.

# С yield from
def chain_with_yield_from(iter1, iter2):
    yield from iter1
    yield from iter2

print(list(chain_with_yield_from(range(3), "ABC")))
# Вывод: [0, 1, 2, 'A', 'B', 'C']

Основные преимущества:

  • Краткость и читаемость: Заменяет вложенный цикл for ... yield, делая намерение очевидным.
  • Производительность: Делегирование происходит на уровне интерпретатора, что эффективнее ручного перебора в Python-коде.
  • Двусторонняя связь: yield from не только получает значения, но и пробрасывает вызовы .send(), .throw() и .close() напрямую в подгенератор. Это критически важно для продвинутых сценариев использования генераторов, включая корутины.
  • Основа для async/await: Механизм await в асинхронных функциях построен на тех же принципах делегирования, что и yield from.