2013-05-27 51 views
29

在Python 2中,當函數定義中的return與yield一起出現錯誤。但是對於Python中的這種代碼3.3返回發生器以及Python中的yield 3.3

def f(): 
    return 3 
    yield 2 

x = f() 
print(x.__next__()) 

在函數中使用yield並沒有錯誤。但是,如果調用函數__next__,則會引發異常StopIteration。爲什麼不只是返回值3?這個回報是否被忽略?

+0

有趣......如果我嘗試'def f():'就像在Python 3.2.5中那樣,我得到:'SyntaxError:'在參數裏面返回'generator'。 (我知道,3.2.x已經過時了......) – torek

+0

Ive使用Python 3.3.1 – scdmb

回答

36

這是一項新功能Python 3.3(作爲註釋註釋,它甚至在3.2中不起作用)。就像發電機中的return長期等效於raise StopIteration(),發電機中的return <something>現在相當於raise StopIteration(<something>)。出於這個原因,你看到的異常應該打印爲StopIteration: 3,並且該值可以通過異常對象上的屬性value訪問。如果發生器被委派使用(也是新的)語法,則結果如下。詳情請參閱PEP 380

def f(): 
    return 1 
    yield 2 

def g(): 
    x = yield from f() 
    print(x) 

# g is still a generator so we need to iterate to run it: 
for _ in g(): 
    pass 

這將打印1,但不2

+1

除外(不適用python 3.4.3)。 – mcepl

+0

@mcepl謝謝,現在修復。我的例子並沒有真正運行生成器。 – delnan

+0

@mcepl 3.4.3哪部分「不」?我假設你指的是它所說的「如果生成器被委託使用語法中的(也是新的)yield,那就是結果。」我剛剛在3.4.3中試過,並且yield from不會返回「返回的」StopException值,這讓我感到非常奇怪和驚訝。但現在我已經考慮了5秒,這是有道理的,因爲外部發電機在內部發電機完成後繼續運行,並且當外部發電機完成時,它會發出自己的StopIteration;而內發電機發出的氣體漂浮進入乙醚。 – allyourcode

18

返回值不被忽略,但生成器只有產量值,一個return只是結束生成器,在這種情況下是早期的。在這種情況下,推進發電機永遠不會達到yield聲明。

每當迭代器達到要產生的值的'結束'時,必須提出必須。發電機也不例外。對於Python 3.3然而,任何return表情變得異常的值:

>>> def gen(): 
...  return 3 
...  yield 2 
... 
>>> try: 
...  next(gen()) 
... except StopIteration as ex: 
...  e = ex 
... 
>>> e 
StopIteration(3,) 
>>> e.value 
3 

使用next()功能來推進,而不是直接調用.__next__()迭代器:

print(next(x)) 
+1

'return'帶有一個值不會被忽略,它可以是一個語法錯誤(在3.2和更早版本中)或者不被忽略(在3.3以後)。 – delnan

+0

@delnan:該值未被使用;你不能使用'return'來代替yield。該函數結束,所以引發'StopIteration'並且返回值最多被丟棄。 OP **在3.3之前知道**返回值是語法錯誤。 –

+1

'return'確實不是'yield'的替代品,但其值是* not *徒勞。它可以作爲異常對象的屬性使用,'yield from'可以方便地訪問它。 – delnan