讓你的python知識更上一次樓,推薦一個url:http://www.ibm.com/developerworks/cn/views/opensource/libraryview.jsp?sort_by=&show_abstract=true&show_all=&search_flag=&contentarea_by=Open+source&search_by=python&topic_by=-1&type_by=%E6%89%80%E6%9C%89%E7%B1%BB%E5%88%AB&ibm-search=%E6%90%9C%E7%B4%A2
清單 5. 使用 yield 的第四版
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print b
a, b = b, a + b
n = n + 1
'''
第四個版本的 fab 和第一版相比,僅僅把 print b 改為了 yield b,就在保持簡潔性的同時獲得了 iterable 的效果。
調用第四版的 fab 和第二版的 fab 完全一緻:
>>> for n in fab(5):
... print n
...
1
1
2
3
5
簡單地講,yield 的作用就是把一個函數變成一個 generator,帶有 yield 的函數不再是一個普通函數,Python 解釋器會将其視為一個 generator,調用 fab(5) 不會執行 fab 函數,而是傳回一個 iterable 對象!在 for 循環執行時,每次循環都會執行 fab 函數内部的代碼,執行到 yield b 時,fab 函數就傳回一個疊代值,下次疊代時,代碼從 yield b 的下一條語句繼續執行,而函數的本地變量看起來和上次中斷執行前是完全一樣的,于是函數繼續執行,直到再次遇到 yield。
也可以手動調用 fab(5) 的 next() 方法(因為 fab(5) 是一個 generator 對象,該對象具有 next() 方法),這樣我們就可以更清楚地看到 fab 的執行流程:
清單 6. 執行流程
>>> f = fab(5)
>>> f.next()
1
>>> f.next()
1
>>> f.next()
2
>>> f.next()
3
>>> f.next()
5
>>> f.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
當函數執行結束時,generator 自動抛出 StopIteration 異常,表示疊代完成。在 for 循環裡,無需處理 StopIteration 異常,循環會正常結束。
我們可以得出以下結論:
一個帶有 yield 的函數就是一個 generator,它和普通函數不同,生成一個 generator 看起來像函數調用,但不會執行任何函數代碼,直到對其調用 next()(在 for 循環中會自動調用 next())才開始執行。雖然執行流程仍按函數的流程執行,但每執行到一個 yield 語句就會中斷,并傳回一個疊代值,下次執行時從 yield 的下一個語句繼續執行。看起來就好像一個函數在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 傳回目前的疊代值。
yield 的好處是顯而易見的,把一個函數改寫為一個 generator 就獲得了疊代能力,比起用類的執行個體儲存狀态來計算下一個 next() 的值,不僅代碼簡潔,而且執行流程異常清晰。