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

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

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

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

yield 是一個(gè)類似 return 的關(guān)鍵字。當(dāng)我們調(diào)用這個(gè)函數(shù)的時(shí)候并不是返回計(jì)算的結(jié)果,而是返回一個(gè)生成器。只有迭代這個(gè)生成器的時(shí)候才會(huì)計(jì)算結(jié)果。
for i in mygenerator:第一次循環(huán)的時(shí)候函數(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ù)掛起。直到生成器里沒(méi)有值可以返回就結(jié)束。
yield 可以返回值,但是不會(huì)結(jié)束函數(shù)的執(zhí)行,如果函數(shù)后面還有代碼,同樣是可以執(zhí)行的。

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

但是用生成器可以創(chuàng)建成功,需要使用的時(shí)候再?gòu)纳善髦腥〕觥?/p>

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

大牛的寫法是這樣子的

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