2016-08-12 4 views
0

Я использую python 3.5. Когда я попытался вернуть экземпляр функции генератора, и я получаю ошибку StopIteration. Зачем?Невозможно вернуть экземпляр генератора. Зачем?

вот мой код:

>>> def gen(start, end): 
... '''generator function similar to range function''' 
... while start <= end: 
...  yield start 
...  start += 1 
... 
>>> def check(ingen, flag=None): 
... if flag: 
...  for n in ingen: 
...   yield n*2 
... else: 
...  return ingen 
... 
>>> # Trigger else clause in check function 
>>> a = check(gen(1,3)) 
>>> next(a) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration: <generator object gen at 0x7f37dc46e828> 

Похоже, что генератор как-то исчерпал до пункта остальное возвращает генератор.

Он отлично работает с этой функцией:

>>> def check_v2(ingen): 
...  return ingen 
... 
>>> b = check_v2(gen(1, 3)) 
>>> next(b) 
1 
>>> next(b) 
2 
>>> next(b) 
3 
+0

@martineau это прекрасно в Python 3 – wroniasty

+0

@wroniasty: Из того, что я только что прочитал, это прекрасно только в Python 3.3+ – martineau

ответ

3

В Python, если в функции присутствует yield, то Python рассматривает его как генератор. В генераторе любое возвращение поднимет StopIteration с возвращенным значением. Это новая функция в Python 3.3: см. PEP 380 и here. check_v2 работает, потому что он не содержит yield и поэтому является нормальной функцией.

Есть два способа сделать то, что вы хотите:

  • Изменить return к yield в check.
  • Есть ловушки абонента StopIteration, как показано ниже

    try: 
        next(a) 
    except StopIteration as ex: 
        print(ex.value) 
    
2

Когда генератор достигает его return заявление (явное или нет), что повышает StopIteration. Поэтому, когда вы заканчиваете итерацию return ingen.

check_v2 не является генератором, так как он не содержит инструкции yield, поэтому он работает.

1

Как уже сказал, если вы возвращаете от генератора, это означает, что генератор остановилось давая элементы, которые поднимают StopIteration независимо Вы возвращаетесь.

Это означает, что check фактически возвращает пустой итератор.

Если вы хотите возвратить результаты другого генератора, вы можете использовать yield from:

def check(ingen, flag=None): 
    if flag: 
     for n in ingen: 
      yield n*2 
    else: 
     yield from ingen 
+1

Спасибо, что открыли глаза для синтаксиса 'yield from'. +1 –

+1

Интересно, что это также с 'yield from', что coroutines реализованы (были, на самом деле, теперь это собственный код операции) – pistache

0

См PEP 380:

В генераторе, оператор

return value 

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

raise StopIteration(value) 

за исключением того, что в настоящее время исключение не может быть уловлено except статьи в возвращающем генераторе.

Это новая функция в Python 3.3.

Смежные вопросы