Вопрос с собеседования · Python

Что делают send, throw и yield from у генераторов?

MiddleИтераторы и генераторы
Ещё спрашивают так:
  • Как генераторы связаны с корутинами?
Коротко

Генератор — не только источник значений: send(x) передаёт значение внутрь (оно становится результатом выражения yield), throw(exc) бросает исключение в точке yield, close() завершает. yield from делегирует подгенератору: пробрасывает значения, send и throw, а возвращает его return.

  • Первый send — только send(None) или next(): генератор ещё не дошёл до yield
  • Return в генераторе — StopIteration.value
  • На этих механизмах исторически построен asyncio (до async/await)

А ещё Сейчас send используют редко — в основном yield from для композиции генераторов

Подробно

send превращает генератор в сопрограмму с состоянием: накопители, конечные автоматы, парсеры, которым данные подаются порциями.

yield from (PEP 380) решает две задачи: короткая запись for x in sub: yield x и прозрачная передача send, throw и возвращаемого значения между вызывающим и подгенератором.

Связь с async/await. До Python 3.5 корутины asyncio были генераторами с yield from; цикл событий двигал их через send. Нативные корутины async def — отдельный тип, но устроены по той же схеме: await — аналог yield from, приостанавливающий выполнение до готовности.

Пример

def averager():
    total = count = 0
    avg = None
    while True:
        x = yield avg
        total += x; count += 1
        avg = total / count

g = averager(); next(g)
g.send(10)   # 10.0
g.send(20)   # 15.0

def flatten(items):
    for x in items:
        if isinstance(x, list):
            yield from flatten(x)
        else:
            yield x

Что хотят услышать

  • send, throw, close.
  • yield from и возвращаемое значение.
  • Связь с корутинами.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗yield from только перебирает значения подгенератора: send в него не попадает, а return в генераторе запрещён
  • ✗Первым вызовом можно отправить send(42)
  • ✓send(x) делает x результатом yield; yield from делегирует подгенератору и возвращает его return
  • ✗throw завершает генератор, не возбуждая исключения внутри

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования