Разница между `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: Синтаксис для делегирования субгенератору.