日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
創(chuàng)新互聯(lián)Python教程:神秘而強(qiáng)大的Python生成器精講

一、 生成器(generator)概念

成都創(chuàng)新互聯(lián)專注于雙峰網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供雙峰營(yíng)銷型網(wǎng)站建設(shè),雙峰網(wǎng)站制作、雙峰網(wǎng)頁(yè)設(shè)計(jì)、雙峰網(wǎng)站官網(wǎng)定制、微信小程序定制開(kāi)發(fā)服務(wù),打造雙峰網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供雙峰網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。

生成器是一個(gè)特殊的迭代器,它保存的是算法,每次調(diào)用next()或send()就計(jì)算出下一個(gè)元素的值,直到計(jì)算出最后一個(gè)元素,沒(méi)有更多的元素時(shí),拋出StopIteration。生成器有兩種類型,一種是生成器表達(dá)式(又稱為生成器推導(dǎo)),一種是生成器函數(shù)。

二、 生成器表達(dá)式

生成器表達(dá)式是通過(guò)一個(gè)Python表達(dá)式語(yǔ)句去計(jì)算一系列數(shù)據(jù),但生成器定義的時(shí)候數(shù)據(jù)并沒(méi)有生成,而是返回一個(gè)對(duì)象,這個(gè)對(duì)象只有在需要的時(shí)候才根據(jù)表達(dá)式計(jì)算當(dāng)前需要返回的數(shù)據(jù):

生成器表達(dá)式來(lái)源于迭代和列表解析(列表解析后面章節(jié)介紹)的組合,生成器和列表解析類似,但是它使用小括號(hào)而不是中括號(hào)。生成器返回按需產(chǎn)生結(jié)果的一個(gè)對(duì)象,而不是一次構(gòu)建一個(gè)結(jié)果列表;

生成器表達(dá)式的語(yǔ)法如下:

(expr for iter_var in iterable)
(expr for iter_var in iterable if cond_expr)

其中:

expr為計(jì)算 生成器元素值的表達(dá)式

for iter_var in iterable iter_var:表示針對(duì)在可迭代對(duì)象iter_var中的每個(gè)元素進(jìn)行表達(dá)式運(yùn)算

if cond_exp:表示可迭代對(duì)象中的元素需要滿足指定條件才會(huì)參與表達(dá)式運(yùn)算

說(shuō)明

直接在一對(duì)既有的小括號(hào)內(nèi)(如在函數(shù)調(diào)用中)使用生成器表達(dá)式時(shí),無(wú)需再添加一對(duì)小括號(hào)。例如:sum(i ** 2 for i in range(10));

生成器表達(dá)式與列表解析的語(yǔ)法非常象,由于涉及部分相關(guān)的函數(shù),在列表解析相關(guān)的章節(jié)老猿再回頭介紹一下生成器表達(dá)式有關(guān)的內(nèi)容。

三、 生成器函數(shù)

生成器函數(shù)是一種語(yǔ)句中包含yield關(guān)鍵詞的特殊的函數(shù),它本身是一個(gè)迭代器,外部需要訪問(wèn)該迭代器數(shù)據(jù)的代碼通過(guò)調(diào)用next函數(shù)(或迭代器的__next__方法)或send方法,觸發(fā)函數(shù)執(zhí)行計(jì)算并通過(guò)yield返回一個(gè)計(jì)算結(jié)果數(shù)據(jù),返回?cái)?shù)據(jù)后該函數(shù)立即停止執(zhí)行,函數(shù)狀態(tài)會(huì)保存在本地變量中,直到外部下次調(diào)用再激活,從上次停止執(zhí)行部分開(kāi)始執(zhí)行。

1、 關(guān)于生成器函數(shù)與調(diào)用方的執(zhí)行過(guò)程解析

生成器函數(shù)定義示意代碼(非可執(zhí)行代碼)如下:

def fun():

初始化

循環(huán):

計(jì)算得到k

nRet=yield k

其他循環(huán)代碼

上面代碼示意表示:生成器函數(shù)運(yùn)行時(shí)計(jì)算得到結(jié)果k通過(guò)yield返回?cái)?shù)據(jù)k給調(diào)用方,返回k給調(diào)用方之后,生成器函數(shù)停止執(zhí)行,yield的調(diào)用執(zhí)行結(jié)果并沒(méi)有返回給生成器函數(shù), nRet的賦值也并沒(méi)有執(zhí)行,等待下次調(diào)用后,再返回yield本身的執(zhí)行結(jié)果,并繼續(xù)后續(xù)循環(huán)代碼,直到再次執(zhí)行yield。

老猿通過(guò)驗(yàn)證理解有幾個(gè)細(xì)節(jié)在此說(shuō)明一下:

a) yield函數(shù)的執(zhí)行是一條語(yǔ)句,但實(shí)際執(zhí)行時(shí)該語(yǔ)句被分解成兩部分,第一部分是將計(jì)算結(jié)果k返回給send或next調(diào)用處(下稱觸發(fā)方),保存當(dāng)前環(huán)境,暫停執(zhí)行,另一部分就是恢復(fù)當(dāng)前環(huán)境,返回yield本身的執(zhí)行結(jié)果給生成器函數(shù)的調(diào)用處,并繼續(xù)往下執(zhí)行后續(xù)循環(huán)。每次調(diào)用yield時(shí),除了第一次是從第一部分執(zhí)行,后續(xù)都是從第二部分開(kāi)始執(zhí)行。

b) yield返回值(nRet記下來(lái)的值)在觸發(fā)方為next(含__next__方法,下同)時(shí),為None,如果觸發(fā)方是send,則該值為send方法參數(shù)中的發(fā)送值;

c) 生成器函數(shù)在調(diào)用時(shí)只是生成一個(gè)生成器實(shí)例,并沒(méi)有真正執(zhí)行,真正執(zhí)行只有第一次通過(guò)next觸發(fā)時(shí)才會(huì)進(jìn)入函數(shù)執(zhí)行,注意第一次觸發(fā)不能是send方式觸發(fā)。

2) 調(diào)用生成器代碼示意

def main():

初始化

f= fun()
next(f)

循環(huán):

其他循環(huán)代碼

nRet=send(x)

其他循環(huán)代碼

上面代碼示意表示:調(diào)用方執(zhí)行自身初始化,然后進(jìn)行生成器函數(shù)的初始化,然后執(zhí)行循環(huán)迭代訪問(wèn)生成器函數(shù)的數(shù)據(jù)。

同樣有幾個(gè)細(xì)節(jié)老猿在此說(shuō)明一下:

a) f= fun(),這個(gè)語(yǔ)句不會(huì)進(jìn)入函數(shù)執(zhí)行,只是生成一個(gè)生成器實(shí)例f

b) 第一個(gè)next調(diào)用只有循環(huán)代碼中使用send觸發(fā)時(shí)才需要,如果循環(huán)中用next則無(wú)需先執(zhí)行一次send;

c) 第一個(gè)next執(zhí)行時(shí)會(huì)觸發(fā)調(diào)用生成器函數(shù),從生成器第一行代碼開(kāi)始執(zhí)行;后續(xù)的next或send執(zhí)行,不再執(zhí)行生成器函數(shù)的初始化部分,只是從yield的第二部分開(kāi)始執(zhí)行,第二部分執(zhí)行時(shí)應(yīng)該在生成器函數(shù)的循環(huán)迭代代碼內(nèi),因此此后執(zhí)行還是在生成器函數(shù)的循環(huán)代碼內(nèi)循環(huán),直到遇到y(tǒng)ield語(yǔ)句,執(zhí)行完yield語(yǔ)句的第一部分邏輯掛起函數(shù)等待再次出發(fā);

d) nRet記錄的返回值就是生成器函數(shù)yield后面返回給觸發(fā)方的數(shù)據(jù)。

2、 下面是一個(gè)老猿編寫的模擬存快遞包裹的生成器函數(shù)及其調(diào)用代碼,每執(zhí)行一次存包裹的函數(shù)就掛起,主程序等待確認(rèn)是否繼續(xù)循環(huán),如果不繼續(xù)則退出,代碼如下:

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+上次循環(huán)yield的返回值
print(‘PutPackage:After Yield, nRet=’,nRet)
if not nRet: continue
def mainf():
print(‘mainf start call PutPackage …’)
vPutPackage=PutPackage() #只是返回生成器generator對(duì)象
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) #觸發(fā)—1給生成器函數(shù)提示函數(shù)退出
except StopIteration:pass
break
print(‘mainf loop start call send …’)
nRet=vPutPackage.send(random.randint(10000,99999)) #產(chǎn)生一個(gè)隨機(jī)包裹編號(hào)觸發(fā)給生成器函數(shù)
print(‘mainf loop after call send ,nRet=’,nRet)
sConfirm=input(“是否準(zhǔn)備結(jié)束存件取件循環(huán)(Y或y是,否則繼續(xù)循環(huán)):”)
if sConfirm.strip().upper()==‘Y’:
bBreak=True
print("\n")
mainf()

執(zhí)行結(jié)果如下,大家對(duì)照前面的執(zhí)行過(guò)程解析理解一下:

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

是否準(zhǔn)備結(jié)束存件取件循環(huán)(Y或y是,否則繼續(xù)循環(huán)):n

mainf loop start call send …
PutPackage:After Yield, nRet= 22204
PutPackage:Before Yield…
mainf loop after call send ,nRet= PutPackage22204

是否準(zhǔn)備結(jié)束存件取件循環(huán)(Y或y是,否則繼續(xù)循環(huán)):y

PutPackage:After Yield, nRet= -1

上述代碼中為什么要捕獲異常?這是因?yàn)樽詈笠粋€(gè)send(-1)時(shí),是從yield第二部分執(zhí)行,執(zhí)行到循環(huán)“if nRet<1 : break”語(yǔ)句就會(huì)終止循環(huán),不會(huì)再通過(guò)yield向觸發(fā)方返回值,此時(shí)send執(zhí)行就會(huì)出現(xiàn)迭代結(jié)束的異常。

3、 生成器函數(shù)的其他說(shuō)明

Python使用生成器對(duì)延遲操作提供了支持。所謂延遲操作,是指在需要的時(shí)候才產(chǎn)生結(jié)果,而不是立即產(chǎn)生結(jié)果。這有利于節(jié)省內(nèi)存,特別是生成器進(jìn)行科學(xué)計(jì)算時(shí)很有用;

生成器就是迭代器,除了next方法外,也可以通過(guò)for循環(huán)來(lái)遍歷出生成器中的內(nèi)容;

生成器除了前面介紹的__next__、send方法外,還有throw、close方法:

a) throw(type[, value[, traceback]]):該方法在生成器暫停的位置引發(fā) type 類型的異常,并返回該生成器函數(shù)所產(chǎn)生的下一個(gè)值。 如果生成器沒(méi)有產(chǎn)生下一個(gè)值就退出,則將引發(fā) StopIteration 異常。 如果生成器函數(shù)沒(méi)有捕獲傳入的異常,或引發(fā)了另一個(gè)異常,則該異常會(huì)被傳播給調(diào)用者。該方法可以解決上面案例捕獲異常的處理

b) close():在生成器函數(shù)暫停的位置引發(fā) GeneratorExit。 如果之后生成器函數(shù)正常退出、關(guān)閉或引發(fā) GeneratorExit(由于未捕獲該異常) 則關(guān)閉并返回其調(diào)用者。 如果生成器產(chǎn)生了一個(gè)值,關(guān)閉會(huì)引發(fā) RuntimeError。 如果生成器引發(fā)任何其他異常,它會(huì)被傳播給調(diào)用者。 如果生成器已經(jīng)由于異?;蛘M顺鰟t close() 不會(huì)做任何事。通過(guò)觸發(fā)方調(diào)用close方法可以直接關(guān)閉生成器,而不需要象上面案例一樣在生成器函數(shù)內(nèi)判斷send發(fā)送的數(shù)據(jù)來(lái)進(jìn)行退出。


新聞標(biāo)題:創(chuàng)新互聯(lián)Python教程:神秘而強(qiáng)大的Python生成器精講
標(biāo)題鏈接:http://www.5511xx.com/article/dheoehh.html