Python關(guān)鍵字yield-大牛必須掌握的高端語法
小白:大牛哥,剛才看到有一個函數(shù)不使用return返回結(jié)果,而是使用yield關(guān)鍵字返回結(jié)果,看不太明白,Python中yield關(guān)鍵字的用途是什么,它有什么作用呀?
大牛: 要想理解yield的作用,你必須了解什么是生成器(generators),了解生成器之前(generators)你需要先去了解什么是可迭代對象(iterables)。
大牛:小白啊,今天你大牛哥我剛好有空,給你說道說道這個yield的作用。讓你開開眼界,看看我大牛都是怎么寫出牛逼代碼的。
小白:好呀好呀!!!
大牛:我們先來看看什么是可迭代對象(iterables)。
當(dāng)你創(chuàng)建了一個列表,你可以遍歷這個列表讀取它的每一個元素,逐個讀取列表元素的過程稱為迭代(iteration)。

上面代碼中 mylist 就是可迭代對象(iterables),使用列表推導(dǎo)式生成的對象也是可迭代對象

向這種可以使用for ... in .. 語法去迭代的對象都是可迭代對象。
大牛:小白,明白什么是可迭代對象了嗎?你來說一說Python里面有那些常見的可迭代對象。
小白:明白了??梢允褂胒or...in...獲取里面元素的對象就是可迭代對象,像字典,列表,元組,字符串都是可迭代對象。大牛哥我說的沒錯吧!
大牛:給你32個贊!!不錯,一點就通。知道什么是可迭代對象后繼續(xù)來看生成器(generators)。
生成器是迭代器(iterators),但是只能迭代一次,生成器不會將所有值存儲在內(nèi)存中,而是實時的生成這些值:

將列推導(dǎo)式的 [] 改成了 () 其他并沒有做任何改變,但是mygenerators已經(jīng)不是列表,而是生成器。生成器迭代一次之后就不能再次迭代。計算出0,然后并不保存結(jié)果和狀態(tài)繼續(xù)計算出1,最后計算出4,逐一生成。
這只是創(chuàng)建生成器的一種方式,另外一種方式就是我們今天的主角yield關(guān)鍵字。

yield 是一個類似 return 的關(guān)鍵字。當(dāng)我們調(diào)用這個函數(shù)的時候并不是返回計算的結(jié)果,而是返回一個生成器。只有迭代這個生成器的時候才會計算結(jié)果。
for i in mygenerator:第一次循環(huán)的時候函數(shù)執(zhí)行到y(tǒng)ield關(guān)鍵字位置,返回 i*i的值,然后將函數(shù)掛起(保存函數(shù)執(zhí)行的狀態(tài))。for i in mygenerator:第二次循環(huán)的繼續(xù)執(zhí)行剛才的函數(shù)(掛起的位置),也就是執(zhí)行生成器里面的for循環(huán),返回i*i的值,然后再次將函數(shù)掛起。直到生成器里沒有值可以返回就結(jié)束。
yield 可以返回值,但是不會結(jié)束函數(shù)的執(zhí)行,如果函數(shù)后面還有代碼,同樣是可以執(zhí)行的。

上面的函數(shù)其實沒有什么作用,只是用來演示生成器用法。生成器在那些地方會用到呢?
比如需要創(chuàng)建一個非常大的列表直接使用列表推導(dǎo)式可能會導(dǎo)致內(nèi)存被耗盡,這代碼是創(chuàng)建不了列表,電腦內(nèi)存不足以保存這個列表。

但是用生成器可以創(chuàng)建成功,需要使用的時候再從生成器中取出。

對比下面這兩段代碼:求1-10的偶數(shù)
大部分人的寫法是這樣的

大牛的寫法是這樣子的

同樣的功能,但是用生成器要簡便很多。
yield 的好處:
1.不會將所有數(shù)據(jù)取出來存入內(nèi)存中;而是返回了一個對象;可以通過對象獲取數(shù)據(jù);用多少取多少,可以節(jié)省內(nèi)存空間。
2.除了能返回一個值,還不會終止循環(huán)的運行
大牛:咳咳!一口氣講了這么多,差點就要把大牛我累掛了。小白同學(xué),聽明白了嗎?
小白:哦,原來yield是這么個用法。謝謝大牛哥!經(jīng)大牛哥這么一說,我發(fā)現(xiàn)以前我寫的代碼很多都可以用yield寫成生成器啊!就拿你上面求偶數(shù)例子吧,采用yield的寫法效率是否比普通寫法高呢?
大牛:效率肯定比較高的,看下面的對比
def test(): for i in range(1, 11000000): if i % 2 == 0: yield idef test1(): result = [] for i in range(1, 11000000): if i % 2 == 0: result.append(i) return result
0.8925411701202393 # 生成器寫法耗時
1.1444191932678223 # 普通寫法耗時
小白:哇!老板就經(jīng)常嫌棄我寫的代碼執(zhí)行效率低,每次我都是拿Python本身執(zhí)行效率就比較低的理由去搪塞老板,原來還可以在這些細節(jié)上做優(yōu)化的。
小白:聽大牛哥一席話,勝讀一本Python核心編程。老板叫我回去改BUG了 emememem。
大牛:坐看庭前花開花落,笑看天邊云卷云舒。泡一杯咖啡,坐等下班。
產(chǎn)品經(jīng)理:大牛,你寫的代碼又出BUG了,還不趕緊回來看看。你是不想下班了吧!