一、 生成器(generator)概念
生成器是乙個特殊的迭代器,它儲存的是演算法,每次呼叫next()或send()就計算出下乙個元素的值,直到計算出最後乙個元素,沒有更多的元素時,丟擲stopiteration。生成器有兩種型別,一種是生成器表示式(又稱為生成器推導),一種是生成器函式。
二、 生成器表示式
生成器表示式是通過乙個python表示式語句去計算一系列資料,但生成器定義的時候資料並沒有生成,而是返回乙個物件,這個物件只有在需要的時候才根據表示式計算當前需要返回的資料:
生成器表示式**於迭代和列表解析(列表解析後面章節介紹)的組合,生成器和列表解析類似,但是它使用小括號而不是中括號。生成器返回按需產生結果的乙個物件,而不是一次構建乙個結果列表;
生成器表示式的語法如下:
(expr for iter_var in iterable)
(expr for iter_var in iterable if cond_expr)
其中:
expr為計算 生成器元素值的表示式生成器函式定義示意**(非可執行**)如下:
def fun():
初始化迴圈:
計算得到k
nret=yield k
其他迴圈**
生成器函式執行時計算得到結果k通過yield返回資料k給呼叫方,返回k給呼叫方之後,生成器函式停止執行,yield的呼叫執行結果並沒有返回給生成器函式, nret的賦值也並沒有執行,等待下次呼叫後,再返回yield本身的執行結果,並繼續後續迴圈**,直到再次執行yield。
幾個細節在此說明一下:
a) yield函式的執行是一條語句,但實際執行時該語句被分解成兩部分,第一部分是將計算結果k返回給send或next呼叫處(下稱觸發方),儲存當前環境,暫停執行,另一部分就是恢復當前環境,返回yield本身的執行結果給生成器函式的呼叫處,並繼續往下執行後續迴圈。每次呼叫yield時,除了第一次是從第一部分執行,後續都是從第二部分開始執行。
b) yield返回值(nret記下來的值)在觸發方為next(含__next__方法,下同)時,為none,如果觸發方是send,則該值為send方法引數中的傳送值;
c) 生成器函式在呼叫時只是生成乙個生成器例項,並沒有真正執行,真正執行只有第一次通過next觸發時才會進入函式執行,注意第一次觸發不能是send方式觸發。
呼叫生成器**示意
上面**示意表示:呼叫方執行自身初始化,然後進行生成器函式的初始化,然後執行迴圈迭代訪問生成器函式的資料。def main():
初始化f= fun()
next(f)
迴圈:其他迴圈**
nret=send(x)
其他迴圈**
同樣有幾個細節在此說明一下:
a) f= fun(),這個語句不會進入函式執行,只是生成乙個生成器例項f
b) 第乙個next呼叫只有迴圈**中使用send觸發時才需要,如果迴圈中用next則無需先執行一次send;
c) 第乙個next執行時會觸發呼叫生成器函式,從生成器第一行**開始執行;後續的next或send執行,不再執行生成器函式的初始化部分,只是從yield的第二部分開始執行,第二部分執行時應該在生成器函式的迴圈迭代**內,因此此後執行還是在生成器函式的迴圈**內迴圈,直到遇到yield語句,執行完yield語句的第一部分邏輯掛起函式等待再次出發;
d) nret記錄的返回值就是生成器函式yield後面返回給觸發方的資料。
2、 下面是乙個模擬存快遞包裹的生成器函式及其呼叫**,每執行一次存包裹的函式就掛起,主程式等待確認是否繼續迴圈,如果不繼續則退出,**如下:
import random
def putpackage():
print(『putpackage start…』)
nret = 123
while true:
if nret<1 : break
print(『putpackage:before yield…』)
nret = yield 』 putpackage』+str(nret) #返回字串putpackage+上次迴圈yield的返回值
print(『putpackage:after yield, nret=』,nret)
if not nret: continue
def mainf():
print(『mainf start call putpackage …』)
vputpackage=putpackage() #只是返回生成器generator物件
bbreak = false
print(『mainf start call next …』)
nret=next(vputpackage) #生成器初始化
print(『mainf end call next,nret=』,nret)
while true:
if bbreak:
try: #為什麼要捕獲異常?
vputpackage.send(-1) #觸發—1給生成器函式提示函式退出
except stopiteration:pass
break
print(『mainf loop start call send …』)
nret=vputpackage.send(random.randint(10000,99999)) #產生乙個隨機包裹編號觸發給生成器函式
print(『mainf loop after call send ,nret=』,nret)
sconfirm=input(「是否準備結束存件取件迴圈(y或y是,否則繼續迴圈):」)
if sconfirm.strip().upper()==『y』:
bbreak=true
print("\n")
mainf()
mainf start call putpackage …
mainf start call next …
putpackage start…
putpackage:before yield…
mainf end call next,nret= putpackage123
mainf loop start call send …
putpackage:after yield, nret= 66468
putpackage:before yield…
mainf loop after call send ,nret= putpackage66468
是否準備結束存件取件迴圈(y或y是,否則繼續迴圈):n
mainf loop start call send …
putpackage:after yield, nret= 22204
putpackage:before yield…
mainf loop after call send ,nret= putpackage22204
是否準備結束存件取件迴圈(y或y是,否則繼續迴圈):y
上述**中為什麼要捕獲異常?這是因為最後乙個send(-1)時,是從yield第二部分執行,執行到迴圈「if nret<1 : break」語句就會終止迴圈,不會再通過yield向觸發方返回值,此時send執行就會出現迭代結束的異常。3、 生成器函式的其他說明
python使用生成器對延遲操作提供了支援。所謂延遲操作,是指在需要的時候才產生結果,而不是立即產生結果。這有利於節省記憶體,特別是生成器進行科學計算時很有用;
生成器就是迭代器,除了next方法外,也可以通過for迴圈來遍歷出生成器中的內容;
生成器除了前面介紹的__next__、send方法外,還有throw、close方法:
a) throw(type[, value[, traceback]]):該方法在生成器暫停的位置引發 type 型別的異常,並返回該生成器函式所產生的下乙個值。 如果生成器沒有產生下乙個值就退出,則將引發 stopiteration 異常。 如果生成器函式沒有捕獲傳入的異常,或引發了另乙個異常,則該異常會被傳播給呼叫者。該方法可以解決上面案例捕獲異常的處理
b) close():在生成器函式暫停的位置引發 generatorexit。 如果之後生成器函式正常退出、關閉或引發 generatorexit(由於未捕獲該異常) 則關閉並返回其呼叫者。 如果生成器產生了乙個值,關閉會引發 runtimeerror。 如果生成器引發任何其他異常,它會被傳播給呼叫者。 如果生成器已經由於異常或正常退出則 close() 不會做任何事。通過觸發方呼叫close方法可以直接關閉生成器,而不需要象上面案例一樣在生成器函式內判斷send傳送的資料來進行退出。
---------------------
python 生成器作用 Python生成器
生成器介紹 在函式內部包含yield關鍵字,那麼該函式執行的結果是生成器,生成器就是迭代器。生成器的功能 把函式結果做成迭代器 以一種優雅的方式封裝好iter,next 提供了一種自己定義迭代器的方式。使用生成器建立乙個迭代器 def a print a yield 11 使用yield,執行後返回...
python生成器好處 Python生成器筆記
python中三大器有迭代器,生成器,裝飾器,本文主要講述生成器。主要從生成器的概念,本質,以及yield關鍵字的使用執行過程。本質 生成器是一類特殊的迭代器,使用了yield關鍵字的函式不再是函式,而是生成器。使用了yield的函式就是生成器 1.yield關鍵字有兩點作用 1.1 yield語句...
python生成器函式 Python 生成器函式
一 生成器 生成器指的是生成器物件,可由生成器表示式得到,也可使用 yield 關鍵字得到乙個生成器函式,呼叫這個函式得到乙個生成器物件 生成器物件,是乙個可迭代物件,是乙個迭代器 生成器物件,是延遲計算 惰性求值的 1.1 生成器函式 函式體重包含 yield 語句的函式,就是生成器函式,呼叫後返...