Разница между `yield from foo()` и `for x в foo(): yield x`

В Python большинство примеров выходов из объясняют это словами:

yield from foo()

похож на

for x in foo(): yield x

С другой стороны, кажется, что это не совсем то же самое, и в нем есть какая-то магия. Мне немного неловко использовать функцию, которая делает магию, которую я не понимаю. Что я должен знать о магии yield from чтобы не попасть в ситуацию, когда магия делает то, чего я не ожидаю? Какие преимущества дает магия, о которых я должен знать?

1 ответ

Решение

Когда foo() возвращает обычную итерацию, оба эквивалентны. "Магия" вступает в игру, когда foo() это тоже генератор. В этот момент yield from foo() а также for x in foo(): yield x дела существенно отличаются.

Генератор также может отправлять данные, используя generator.send() метод. Когда вы используете for петля, yield x выражение "получает" отправленные данные; foo() Генератор никогда не увидит этого. Но когда вы используете yield from отправленные данные идут прямо к чему угодно yield выражение, которому делегирован генератор, в данный момент приостановлено. Другими словами, yield from передает отправленные данные, чтобы их мог получить делегированный генератор.

Вы также можете вызывать исключения в генераторе с помощью generator.throw(); с for случай цикла, исключение возникает из yield x линия, а с yield from исключение передается снова; исключение поднимается внутри foo() вместо.

Вместе это означает, что yield from по сути, заменяет текущий генератор на время делегированной итерации.

Генератор делегирования также получает связь с родительским генератором, когда .value атрибут StopIteration Возникшее исключение возвращается как значение yield from выражение. Вы можете установить значение этого исключения, используя return <expression> в делегированном foo() генератор, или вы можете использовать raise StopIteration(<expression>) в явном виде.

yield from был введен в язык вместе с PEP 380: Синтаксис для делегирования субгенератору.

Другие вопросы по тегам