возврат и возврат Нет в генераторе: рекомендации PEP - PullRequest
0 голосов
/ 15 мая 2018

В соответствии с PEP 8 мы должны быть последовательными в наших объявлениях функций и гарантировать, что все они имеют одинаковый шаблон возврата, то есть все должны возвращать выражение или все не должны.Однако я не уверен, как применить это к генераторам.

Генератор будет yield значения, пока код их достигает, если только не встречается оператор return, в этом случае он останавливает итерацию,Однако я не вижу ни одного варианта использования, в котором может произойти возврат значения из функции генератора.В этом духе я не понимаю, почему полезно - с точки зрения PEP 8 - завершать такую ​​функцию явным return None.Другими словами, почему мы должны озвучивать выражение return для генераторов, если выражение return достигается только после того, как yield'ing закончился?

Пример: в следующем коде я не вижу, как hello() можно использовать для присвоения 100 переменной (таким образом, используя инструкцию return).Так почему же PEP 8 ожидает, что мы напишем оператор возврата (будь то 100 или None).

def hello():
    for i in range(5):
      yield i

    return 100


h = [x for x in hello()]
g = hello()

print(h)    
# [0, 1, 2, 3, 4]
print(g)
# <generator object hello at 0x7fd2f285a7d8>
# can we ever get 100?

1 Ответ

0 голосов
/ 15 мая 2018

Вы неправильно прочитали PEP8. PEP8 заявляет:

Будьте последовательны в ответных заявлениях. Либо все операторы возврата в функции должны возвращать выражение, либо ни один из них не должен.

(жирный акцент мой)

Вы должны соответствовать тому, как вы используете return в одной функции, а не во всем проекте.

Используйте return, это единственный оператор return в функции.

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

Возвращаемое значение генератора присоединяется к возбужденному исключению StopIteration:

>>> def gen():
...     if False: yield
...     return 'Return value'
...
>>> try:
...     next(gen())
... except StopIteration as ex:
...     print(ex.value)
...
Return value

И это также механизм, с помощью которого yield from производит значение; возвращаемое значение yield from является атрибутом value в исключении StopIteration. Таким образом, генератор может вернуть результат в код, используя result = yield from generator, используя return result:

>>> def bar():
...     result = yield from gen()
...     print('gen() returned', result)
...
>>> next(bar(), None)
gen() returned Return value

Эта функция используется в стандартной библиотеке Python; например в библиотеке asyncio значение StopIteration используется для передачи результатов Task, а декоратор @coroutine использует res = yield from ... для запуска генератора с оболочкой или ожидаемого и передачи через возвращаемое значение.

Итак, с точки зрения PEP-8, для генераторов существует две возможности:

  • Вы используете return для раннего выхода из генератора, скажем, в цикле с if. Используйте return, не нужно добавлять None:

    def foo():
        while bar:
            yield ham
            if spam:
                return
    
  • Вы используете return <something> для выхода и для установки StopIteration.value. Используйте return <something> последовательно во всем генераторе, даже при возврате None:

    def foo():
        for bar in baz:
            yield bar
            if spam:
                return 'The bar bazzed the spam'
        return None
    
...