В чем разница между 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;.