在Python中,我們將帶有 yield 的函數稱之爲 generator(生成器)。generator可以一邊循環一邊計算,是可迭代對象,也就是說可以使用for循環來迭代出generator的各個值。
一、
一般爲了說明generator,都會使用斐波那契數列來舉例,這裏也不例外:
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
yield b
a, b = b, a + b
n = n + 1
如結果所示,調用 fab(5) 並不會執行 fab 函數,而是返回一個 可迭代對象, 每次循環都會執行 fab 函數內部的代碼,執行到 yield b 時,fab 函數就返回一個迭代值,下次迭代時,代碼從 yield b 的下一條語句繼續執行,而函數的本地變量看起來和上次中斷執行前是完全一樣的,函數繼續執行,直到再次遇到 yield或return。
在一個 generator中,如果沒有 return,則默認執行至函數完畢,如果在執行過程中遇見了return,則直接拋出 StopIteration 終止迭代。
二、
與generator有關的很重要的函數有next()和send(parameter)。
因爲generator是可迭代對象,我們可以使用next()來手動迭代其各個值。仍然拿上面fab()函數來舉例,如下圖所示:
send(parameter)函數可以給yield表達式傳值,而next()只能傳遞None進去。因此,某種程度上c.next() 和 c.send(None)的作用是一樣的。來看例子:
可以看到,認爲n=5、m=10是錯誤的!這是因爲yield是一個表達式,(yield 5)本身是有一個返回值的,這個返回值可以由send(parameter)函數傳遞進去:
需要注意的是,第一次調用時不能使用send發送一個非None值,否則會報錯,因爲沒有yield語句來接收這個值。可以使用next()語句或send(None)。
send(parameter) 和 next()這兩個函數是有其自己的返回值的,它們的返回值很特殊,返回的是下一個yield表達式的參數。比如yield 5,則返回5。
因爲for循環迭代generator時,其實是一次次調用了next()函數,直到拋出StopIteration異常爲止。而每次迭代出的值,其實就是next()函數的返回值,也就是yield表達式的參數!