關於Python中的yield

2021-07-22 05:08:45 字數 2928 閱讀 3096

在介紹yield前有必要先說明下python中的迭代器(iterator)和生成器(constructor)。

一、迭代器(iterator)

在python中,for迴圈可以用於python中的任何型別,包括列表、元祖等等,實際上,for迴圈可用於任何「可迭代物件」,這其實就是迭代器

迭代器是乙個實現了迭代器協議的物件,python中的迭代器協議就是有next方法的物件會前進到下一結果,而在一系列結果的末尾是,則會引發stopiteration。任何這類的物件在python中都可以用for迴圈或其他遍歷工具迭代,迭代工具內部會在每次迭代時呼叫next方法,並且捕捉stopiteration異常來確定何時離開。

使用迭代器乙個顯而易見的好處就是:每次只從物件中讀取一條資料,不會造成記憶體的過大開銷。

比如要逐行讀取乙個檔案的內容,利用readlines()方法,我們可以這麼寫:

1

2

for line in

open

("test.txt"

).readlines():

print line

這樣雖然可以工作,但不是最好的方法。因為他實際上是把檔案一次載入到記憶體中,然後逐行列印。當檔案很大時,這個方法的記憶體開銷就很大了。

利用file的迭代器,我們可以這樣寫:

1

2

for line in

open

("test.txt"

): #use file iterators

print line

這是最簡單也是執行速度最快的寫法,他並沒顯式的讀取檔案,而是利用迭代器每次讀取下一行。

二、生成器(constructor)

生成器函式在python中與迭代器協議的概念聯絡在一起。簡而言之,包含yield語句的函式會被特地編譯成生成器。當函式被呼叫時,他們返回乙個生成器物件,這個物件支援迭代器介面。函式也許會有個return語句,但它的作用是用來yield產生值的。

不像一般的函式會生成值後退出,生成器函式在生成值後會自動掛起並暫停他們的執行和狀態,他的本地變數將儲存狀態資訊,這些資訊在函式恢復時將再度有效

123

4567

8

>>>

def g(n):

... for i in

range

(n):

... yield i **

2...

>>>

for i in g(5):

... print i,":",

...0 : 1 : 4 : 9 : 16 :

要了解他的執行原理,我們來用next方法看看:

123

4567

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數列:

123

4567

8910

def fab(

max):

a,b = 0,1

while a <

max:

yield a

a, b = b, a+b

>>>

for i in fab(

20):

... print i,",",

...0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 ,

看到這裡應該就能理解生成器那個很抽象的概念了吧~~

感覺跟遞迴很像。

下面我們用yield來讀檔案:

隨便建乙個檔案類似12

3一般我們讀檔案可以這樣讀

def read(file):

with open(file) as f:

for line in f.readlines():

print line

if __name__ == '__main__':

read("inputfile.txt")

但其實readlines

這樣子一下全讀進來了,佔記憶體。

我們用yield讀

def read(file):

with open(file) as f:

for line in f:

yield line.strip()

if __name__ == '__main__':

reader = read("inputfile.txt")

line = reader.next()

while line:

line = reader.next()

print line

或者這樣

def read(file):

with open(file) as f:

for line in f:

yield line.strip()

if __name__ == '__main__':

reader = read("inputfile.txt")

for line in reader:

print line

關於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迴圈可用於任何 可迭代物件 這其實就是迭代器 迭代器是乙個實現了迭...