在介紹yield前有必要先說明下python中的迭代器(iterator)和生成器(constructor)。
一、迭代器(iterator)
在python中,for迴圈可以用於python中的任何型別,包括列表、元祖等等,實際上,for迴圈可用於任何「可迭代物件」,這其實就是迭代器
迭代器是乙個實現了迭代器協議的物件,python中的迭代器協議就是有next方法的物件會前進到下一結果,而在一系列結果的末尾是,則會引發stopiteration。任何這類的物件在python中都可以用for迴圈或其他遍歷工具迭代,迭代工具內部會在每次迭代時呼叫next方法,並且捕捉stopiteration異常來確定何時離開。
使用迭代器乙個顯而易見的好處就是:每次只從物件中讀取一條資料,不會造成記憶體的過大開銷。
比如要逐行讀取乙個檔案的內容,利用readlines()方法,我們可以這麼寫:
12
forlineinopen
("test.txt"
).readlines():
printline
這樣雖然可以工作,但不是最好的方法。因為他實際上是把檔案一次載入到記憶體中,然後逐行列印。當檔案很大時,這個方法的記憶體開銷就很大了。
利用file的迭代器,我們可以這樣寫:
12
forlineinopen
("test.txt"
): #use file iterators
printline
這是最簡單也是執行速度最快的寫法,他並沒顯式的讀取檔案,而是利用迭代器每次讀取下一行。
二、生成器(constructor)
生成器函式在python中與迭代器協議的概念聯絡在一起。簡而言之,包含yield語句的函式會被特地編譯成生成器。當函式被呼叫時,他們返回乙個生成器物件,這個物件支援迭代器介面。函式也許會有個return語句,但它的作用是用來yield產生值的。
不像一般的函式會生成值後退出,生成器函式在生成值後會自動掛起並暫停他們的執行和狀態,他的本地變數將儲存狀態資訊,這些資訊在函式恢復時將再度有效
1234567
8
>>>
defg(n):
...foriinrange
(n):
...yieldi **
2...
>>>
foriing(5):
...printi,":",
...0 : 1 : 4 : 9 : 16 :
要了解他的執行原理,我們來用next方法看看:
1234567
891011
1213
1415
>>> t = g(5)
>>> t.next()
0>>> t.next()
1>>> t.next()
4>>> t.next()
9>>> t.next()
16>>> t.next()
traceback (most recent call last):
file "", line 1,in
stopiteration
在執行完5次next之後,生成器丟擲了乙個stopiteration異常,迭代終止。
再來看乙個yield的例子,用生成器生成乙個fibonacci數列:
1234567
8910
deffab(
max):
a,b = 0,1
whilea <
max:
yielda
a, b = b, a+b
>>>
foriinfab(
20):
...printi,",",
...0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 ,
看到這裡應該就能理解生成器那個很抽象的概念了吧~~
關於Python中的yield
在介紹yield前有必要先說明下python中的迭代器 iterator 和生成器 constructor 一 迭代器 iterator 在python中,for迴圈可以用於python中的任何型別,包括列表 元祖等等,實際上,for迴圈可用於任何 可迭代物件 這其實就是迭代器 迭代器是乙個實現了迭...
關於Python中的yield
在介紹yield前有必要先說明下python中的迭代器 iterator 和生成器 constructor 一 迭代器 iterator 在python中,for迴圈可以用於python中的任何型別,包括列表 元祖等等,實際上,for迴圈可用於任何 可迭代物件 這其實就是迭代器 迭代器是乙個實現了迭...
關於Python中的yield
在介紹yield前有必要先說明下python中的迭代器 iterator 和生成器 constructor 一 迭代器 iterator 在python中,for迴圈可以用於python中的任何型別,包括列表 元祖等等,實際上,for迴圈可用於任何 可迭代物件 這其實就是迭代器 迭代器是乙個實現了迭...