2013-05-27 3 views
4

Существует этот код:Выход против выражения генератора - другой тип возвращается

def f(): 
    return 3 
    return (i for i in range(10)) 

x = f() 
print(type(x)) # int 

def g(): 
    return 3 
    for i in range(10): 
    yield i 

y = g() 
print(type(y)) # generator 

Почему f возвращается int, когда есть оператор возврата генератор? Я думаю, что и выражение генератора возвращают генераторы (по крайней мере, когда оператор return 3 удален), но есть ли другие правила компиляции функций, когда есть возвращаемое выражение генератора и второй раз, когда внутри есть ключевое слово yield?

Это было проверено в Python 3.3

+1

Ваш метод g() неверен, вы не можете смешивать return и yield в той же функции, вы получаете сообщение об ошибке. Вставьте реальный код. –

+2

@ LennartRegebro: Вы можете, по сути, комбинировать возврат и выход в ту же функцию. В Python 3.2 и ранее вы не можете вернуть * значение * (это 'SyntaxError'), но в Python 3.3 и выше вы даже можете это сделать. См. [Возврат в генераторе вместе с доходностью в Python 3.3] (http://stackoverflow.com/q/16780002) –

+0

Ах, хорошо, не знал этого. –

ответ

9

Как скоро, как вы используете yield заявление, в теле функции, она становится генератором. Вызов функции генератора возвращает этот объект генератора. Это уже не нормальная функция; вместо этого вместо этого объект-генератор взял управление.

От yield expression documentation:

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

Когда вызывается функция генератора, она возвращает итератор, известный как генератор. Затем этот генератор управляет выполнением функции генератора. Выполнение начинается, когда вызывается один из методов генератора.

В регулярной функции, вызов этой функции немедленно переключает управление этой функции тела, и вы просто тестируете результат функции, установленное это return заявления. В функции генератора return все еще сигнализирует о конце функции генератора, но в результате возникает исключение StopIteration. Но пока вы не назовете один из четырех методов генератора (.__next__(), .send(), .throw() или .close()), тело функции генератора вообще не выполняется.

Для вашей конкретной функции f() у вас есть регулярная функция, что содержит генератор. Сама функция ничего особенного, кроме того, что она выходит раньше, когда выполняется return 3. Выражение генератора на следующей строке стоит само по себе, оно не влияет на функцию, в которой она определена. Вы можете определить его без функции:

>>> (i for i in range(10)) 
<generator object <genexpr> at 0x101472730> 

Используя выражение генератор производит объект генератора, так же, как с помощью yield в функции, то вызов функции, которая производит объект генератора. Таким образом, вы могли бы назвать g() в f() с тем же результатом, используя выражение генератора:

def f(): 
    return 3 
    return g() 

g() еще функциональный генератор, но использовать его в f() делает не сделать f() функцию генератора тоже. Только yield может это сделать.

2
def f(): 
    return 3 
    return (i for i in range(10)) 

такая же, как

def f(): 
    return 3 

Второй оператор возврата никогда не запускается на выполнение, только при наличии экспрессии генератора в пределах fне сделать это генератор.

1
def f(): 
    return 3 
    #unreachable code below 
    return (i for i in range(10)) 

Я считаю, что вы имели в виду это:

def f(): 
    yield 3 
    yield from (i for i in range(10)) 
0

Возвращение генератор не делает f функцию генератора. Генератор - это всего лишь объект, и объекты-генераторы могут быть возвращены любой функцией. Если вы хотите, чтобы функция f была функцией генератора, вы должны использовать внутри функции функцию yield, как и в случае с g.

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