天天看點

Python 生成器與生成器的應用

1. 生成器:

(1)在 Python 中, 一邊循環一邊計算的機制,稱為生成器(Generator);

(2)生成器是Python中的一個對象,對這個對象進行操作,可以依次生産出按生成器内部運算産生的資料;

(3)生成器可以通過生成器表達式和生成器函數擷取到;

2. 什麼是生成器函數:

        生成器函數指的是函數體中包含yield關鍵字的函數(yield就是專門給生成器用的return)。一般來說,生成器函數和正常函數一樣,事實上也是用正常的def語句編寫的。然而,當建立時,它們被特殊地編譯成一個支援疊代協定的對象。并且在調用的時候它們不會傳回一個結果,它們傳回一個可以出現在任何疊代上下文中的結果生成器。 

3. 狀态挂起

        生成器函數能夠自動挂起并在生成值的時刻恢複之前的狀态并繼續函數的執行。由于生成器函數在挂起時儲存的狀态包含它們的代碼位置和整個局部作用域。yield語句會挂起該函數并向調用者傳加一個值,但同時也保留了足夠的狀态使函數能從它離開的地方繼續。

        與疊代協定內建,疊代器對象定義一個__next__方法(在2.X中的next),它要麼傳回疊代中的下一項,要麼引發一個特殊的StopIteration異常來終止疊代。

        為了支援這一協定,函數必須包含一條 yield語句,該函數将被特别編譯為生成器:它們不再是普通函數,而是作為特定的疊代協定方法來傳回對象的函數。當調用時,它們傳回一個生成器對象,該對象支援用一個自動建立的名為__next__的方法接口,來開始或恢複執行。也就是說,被傳回的生成器對象有一個__next__方法,該方法可以開始這個函數,或者從它上次yield值後的地方恢複,并且在得到一系列值的最後一個時,引發一個StopIteration異常。

4. 成生器函數的應用:

(1)生成器函數是一種“窮人的”多線程機制:它們通過把操作拆分到每一次的yield之間,進而将一個函數的執行交錯地插入它的調用者的工作中。

(2)生成器的send()方法:send()方法相當于一種調用者與生成器之間進行通信的方式,進而能得到影響生成器的操作。值可以通過調用 G.send(value)發送給一個生成器G,手動結束yield延遲,恢複生成器代碼的執行,并且生成器中的yield表達式傳回了發送給send函數的值。

(3)next(G) ,要麼傳回生成器G的下一項,要麼引發一個StopIteration異常,next(G)等同于G.__next__().

def gen():
    for i in range(8):
        x = yield i     # 把 i yield 出去,然後還沒指派就挂起了,等回來時再進行指派
        print(x)


G = gen()
print(G)    # <generator object gen at 0x000001E5FFAB1F48>

X0 = next(G)    # next() 要麼傳回疊代器的下一項,要麼引發一個特殊的StopIteration異常
print("Out of func X0=%d" % X0 if isinstance(X0, int) else "Out of func X0=None")
"""
Out of func X0=0
None   了解:生成器已經把值傳回給了調用者,然後next()又催生成器進行下一個循環,但此時還沒計算出下一個值,就print(x),是以print出來是None(這個None是print(x)列印的)
"""
X1 = next(G)
print("Out of func X1=%d" % X1 if isinstance(X1, int) else "Out of func X1=None")
"""
Out of func X1=1
None
"""
X2 = next(G)
print("Out of func X2=%d" % X2 if isinstance(X2, int) else "Out of func X2=None")
"""
Out of func X2=2
"""
X3 = G.send(77)  # 生送一個值給生成器G,并且生成器中的yield表達式傳回了發送給send()的值
print("Out of func X3=%d" % X3 if isinstance(X3, int) else "Out of func X3=None")
"""
77   (這裡是 print(x) 列印的,send(77)後,馬上恢複指派給了x,然後列印出了 77)
Out of func X3=3
None
"""
X4 = next(G)
print("Out of func X4=%d" % X4 if isinstance(X4, int) else "Out of func X4=None")
"""
Out of func X4=4
None
"""
X5 = G.__next__()   # 跟 next(G)一樣
print("Out of func X5=%d" % X5 if isinstance(X5, int) else "Out of func X5=None")
"""
Out of func X5=5
"""
           

5. 生成器表達式

從文法上來講,生成器表達式就像一般的清單推導一樣,而且也支援所有清單推導的文法(包括if過濾器和循環嵌套),但它們是包括在圓括号中而不是方括号中的(跟元組一樣,它們的圓括号通常是可選的)。

# 清單推導式 build a list
[x**2 for x in range(4)]
# [0, 1, 4, 9]

# 生成器表達式 make an iterable
(x**2 for x in range(4))
# <generator object <genexpr> at 0x00000000029A8288>
           

繼續閱讀