Возврат и выход в ту же функцию

Что именно происходит, когда yield и return используются в одной и той же функции в Python, например?

def find_all(a_str, sub):
    start = 0
    while True:
        start = a_str.find(sub, start)
        if start == -1: return
        yield start
        start += len(sub) # use start += 1 to find overlapping matches

Является ли он еще генератором?

Ответ 1

Да, это еще генератор. return (почти) эквивалентно повышению StopIteration.

PEP 255 говорит:

Спецификация: Return

Функция генератора также может содержать операторы возврата вида:

"return"

Обратите внимание, что выражение expression_list не разрешено в операторах return в тело генератора (хотя, конечно, они могут появляться в тела негенераторных функций, вложенных в генератор).

Когда встречается оператор return, управление продолжается как в любом возвращает функцию, выполняя соответствующие окончательные предложения (если есть существовать). Затем возникает исключение StopIteration, сигнализирующее, что итератор исчерпан. Исключение StopIteration также возникает, если управление течет от конца генератора без эксплицитного возврата.

Обратите внимание, что возврат означает "Я закончил, и у меня нет ничего интересного return", как для функций генератора, так и для негенераторных функций.

Обратите внимание, что возврат не всегда эквивалентен повышению StopIteration: разница заключается в том, как заключать объекты try/except обрабатывали. Например,

>>> def f1():
...     try:
...         return
...     except:
...        yield 1
>>> print list(f1())
[]

потому что, как и в любой функции, возврат просто завершается, но

>>> def f2():
...     try:
...         raise StopIteration
...     except:
...         yield 42
>>> print list(f2())
[42]

потому что StopIteration захватывается голой "исключением", как и любая исключение.

Ответ 2

Да, это все еще генератор. Пустые return или return None могут использоваться для завершения функции генератора. Это эквивалентно повышению a StopIteration (подробнее см. @NPE).

Обратите внимание, что возврат с аргументами, отличными от None, является SyntaxError в версиях Python до 3.3.

Как указано @BrenBarn в комментариях, начиная с Python 3.3, возвращаемое значение теперь передается в StopIteration.

От PEP 380:

В генераторе утверждение

return value

семантически эквивалентно

raise StopIteration(value)

Ответ 3

Существует способ выполнения метода доходности и возврата в функции, которая позволяет вам вернуть значение или генератор.

Вероятно, он не так чист, как вам хотелось бы, но он делает то, что вы ожидаете.

Вот пример:

def six(how_many=None):
    if how_many is None or how_many < 1:
        return None  # returns value

    if how_many == 1:
        return 6  # returns value

    def iter_func():
        for count in range(how_many):
            yield 6
    return iter_func()  # returns generator