В чем разница между raise StopIteration и оператором return в генераторах?
Мне интересно узнать разницу между использованием raise StopIteration
и return
в генераторах.
Например, существует ли разница между этими двумя функциями?
def my_generator0(n):
for i in range(n):
yield i
if i >= 5:
return
def my_generator1(n):
for i in range(n):
yield i
if i >= 5:
raise StopIteration
Я предполагаю, что более "питонический" способ сделать это - второй способ (пожалуйста, поправьте меня, если я ошибаюсь), но насколько я вижу, оба способа поднимают исключение StopIteration
.
Ответы
Ответ 1
Нет необходимости явно поднимать StopIteration
как то, что делает инструкция bare return
для функции генератора - так что да, они одинаковы. Но нет, просто используя return
больше Pythonic.
От: http://docs.python.org/2/reference/simple_stmts.html#the-return-statement (действителен для Python 3.2)
В функции-генераторе оператор return не может включать выражение-list. В этом контексте голый возврат указывает на то, что генератор выполнен и вызовет остановку StopIteration.
Или, как указывает @Bakuriu - семантика генераторов слегка изменилась для Python 3.3, поэтому более подходящим является следующее:
В функции генератора оператор return указывает на то, что генератор выполнен и вызовет повышение StopIteration. Возвращаемое значение (если оно есть) используется как аргумент для построения StopIteration и становится атрибутом StopIteration.value.
Ответ 2
По состоянию на конец 2014 года return
является правильным и raise StopIteration
для завершения генератора находится в графике амортизации. Подробнее см. PEP 479.
Аннотация
Этот PEP предлагает изменение генераторам: когда StopIteration
возникает внутри генератора, он заменяется на RuntimeError
. (Точнее, это происходит, когда исключение вот-вот выйдет из фрейма стека генератора.) Поскольку это изменение обратно несовместимо, функция изначально вводится с помощью инструкции __future__
.
Приемка
Этот PEP был принят BDFL 22 ноября...
Обоснование
Взаимодействие генераторов и StopIteration в настоящее время несколько удивительно и может скрывать неясные ошибки. Неожиданное исключение не должно приводить к тонко измененному поведению, но должно вызывать шумную и легко отлаженную трассировку. В настоящее время StopIteration, случайно возникший внутри функции генератора, будет интерпретироваться как конец итерации контуром, управляющим генератором.
...
Ответ 3
Это правда, они эквивалентны, за исключением того, что один читается, тогда как другой неясен. Это относится к самой первой версии генераторов (PEP 255 в разделе "Спецификация: возврат" ), а последующие улучшения (например, сопрограммы) не меняют этого. 3.3 yield from
(PEP 380) расширяет его до return <expr>
как синтаксический сахар для raise StopIteration(<expr>)
, но это не меняет значения return;
.