生成器的特點(diǎn)是工作到一半,就會(huì)停下來(lái)看別人干活直至有人踢它屁股颗祝,這時(shí)它才繼續(xù)往下干活浊闪。實(shí)現(xiàn)這一功能的精髓要用到y(tǒng)ield。
生成器是一種特殊的迭代器螺戳,因此我們先來(lái)了解一下什么是迭代器规揪。我們都知道著名的斐波那契數(shù)列:1、1温峭、2、3字支、5凤藏、8奸忽、13、21揖庄、34……從第三個(gè)數(shù)開(kāi)始栗菜,每個(gè)數(shù)都可以由其前面的兩個(gè)數(shù)相加得到,這就是一個(gè)迭代過(guò)程蹄梢。很顯然疙筹,這是一個(gè)不收斂的數(shù)列,我們無(wú)法用列表或者使集合去一次性將它們提取出來(lái)禁炒。這時(shí)候而咆,如果我們把這樣一個(gè)迭代過(guò)程封裝成一個(gè)迭代器,只有在調(diào)用一次它的時(shí)候它才進(jìn)行一次迭代幕袱,并且只保留當(dāng)前的迭代結(jié)果暴备,這樣一來(lái),程序的運(yùn)行速度能得到提高们豌,同時(shí)也不會(huì)對(duì)內(nèi)存造成嚴(yán)重的負(fù)擔(dān)涯捻。迭代器可以表示一個(gè)無(wú)限大的數(shù)據(jù)流,也可以表示一個(gè)有限的數(shù)據(jù)流望迎。
從代碼的角度講障癌,所有可以被next()函數(shù)調(diào)用并不斷返回下一個(gè)值的對(duì)象就叫做迭代器:Iterator。與迭代器相近的一個(gè)概念是可迭代對(duì)象(Iterable)辩尊,凡是可用for循環(huán)遍歷的對(duì)象都是可迭代對(duì)象涛浙,比如list、dict和str等对省。但是這幾個(gè)對(duì)象不是迭代器蝗拿,這一點(diǎn)在上一段已經(jīng)從迭代器的特點(diǎn)說(shuō)明,不再贅述蒿涎。然而哀托,世事無(wú)絕對(duì),通過(guò)iter()函數(shù)劳秋,可以將它們變成迭代器仓手。
由此,我們可以建立這樣一個(gè)斐波那契數(shù)列生成器:
def generate():
b,c = 0,1
while True:
b,c = c,b +c #迭代公式
yield c
return "fault" #出錯(cuò)時(shí)的返回值
y = generate() #產(chǎn)生一個(gè)生成器對(duì)象玻淑,但不調(diào)用生成器
for i in range(15): #調(diào)用15次
print(y.__next__(),end=" ") #使用next()方法調(diào)用生成器
yield的作用是讓生成器在這里暫停執(zhí)行嗽冒,執(zhí)行下一條程序指令。當(dāng)下一次調(diào)用next()函數(shù)時(shí)补履,生成器從暫停的地方繼續(xù)往下執(zhí)行添坊。一次,每調(diào)用一次產(chǎn)生一個(gè)值箫锤,調(diào)用15次產(chǎn)生15個(gè)值贬蛙,如下圖所示:
這種類型的生成器并不需要參數(shù)雨女,當(dāng)我們需要給生成器內(nèi)部傳遞參數(shù)時(shí),我們需要用到send()函數(shù)阳准,因?yàn)閚ext()函數(shù)不具備該功能氛堕。看下面這樣一段代碼:
def sing(word1):
print(word1)
while True:
word2 = yield #每次調(diào)用時(shí)生成器都停留在這里
print(word2)
a = sing("如今走過(guò)這世間")
a.send(None) #可以替換成a.__next__()
a.send("萬(wàn)般流連")
上述代碼野蝇,如果不用while循環(huán)讼稚,則沒(méi)辦法使每次調(diào)用的結(jié)果程序都停留在yield這里,而是執(zhí)行完print(word2)變結(jié)束了绕沈,這使程序會(huì)報(bào)錯(cuò)锐想。在第一次使用需要傳遞參數(shù)的生成器時(shí),我們不能直接使用send()函數(shù)傳遞我們想傳遞的參數(shù)七冲,因?yàn)榇藭r(shí)函數(shù)停在yeild痛倚,并不需要到這個(gè)參數(shù)。因此我們可以用next()函數(shù)來(lái)進(jìn)行第一次調(diào)用澜躺,然后再調(diào)用send()傳遞參數(shù)并調(diào)用蝉稳。當(dāng)然,如果我們非要用send()函數(shù)實(shí)現(xiàn)第一次調(diào)用時(shí)掘鄙,應(yīng)該傳遞一個(gè)空參數(shù)耘戚。運(yùn)行結(jié)果如下所示:
至此,大功告成操漠!