成為Python大牛必須要掌握的高端語(yǔ)法——yield

1. 什么是yield

在介紹yield語(yǔ)法之前,首先要向大家說(shuō)明Python中的迭代(iteration)、可迭代(iterable)、迭代器(iterator)以及生成器(Generator)的概念:

迭代是一種對(duì)數(shù)據(jù)的操作,例如針對(duì)一個(gè)list逐一獲取其中的元素的過程就叫做迭代。而可迭代是對(duì)象的一種特性,迭代操作只能針對(duì)擁有可迭代特性的對(duì)象進(jìn)行,常見的可迭代對(duì)象包括數(shù)組、元組、字典等數(shù)據(jù)集合,下面代碼給大家演示了一個(gè)基本的迭代過程:

迭代器也是一種可迭代對(duì)象,與普通的可迭代對(duì)象的區(qū)別在于,迭代器內(nèi)部實(shí)現(xiàn)了next函數(shù)用來(lái)生成每次迭代循環(huán)需要返回的元素。而最后的生成器則又是一種特殊的迭代器,具體體現(xiàn)上就是使用yield語(yǔ)法的函數(shù),講到這里就提到了yield語(yǔ)法,總的來(lái)說(shuō)yield就是用來(lái)產(chǎn)生一個(gè)生成器的語(yǔ)法,例如將上述的迭代過程修改為生成器方式可以這樣寫:

迭代器也是一種可迭代對(duì)象,與普通的可迭代對(duì)象的區(qū)別在于,迭代器內(nèi)部實(shí)現(xiàn)了next函數(shù)用來(lái)生成每次迭代循環(huán)需要返回的元素。而最后的生成器則又是一種特殊的迭代器,具體體現(xiàn)上就是使用yield語(yǔ)法的函數(shù),講到這里就提到了yield語(yǔ)法,總的來(lái)說(shuō)yield就是用來(lái)產(chǎn)生一個(gè)生成器的語(yǔ)法,例如將上述的迭代過程修改為生成器方式可以這樣寫:

上述代碼的my_generator()即返回了一個(gè)生成器對(duì)象,每次循環(huán)時(shí)執(zhí)行到y(tǒng)ield處即返回當(dāng)時(shí)的index的值,到下一次循環(huán)時(shí)將從上次返回的yield處繼續(xù)執(zhí)行,直到index的值不滿足小于5的條件時(shí)結(jié)束整個(gè)函數(shù),此時(shí)也結(jié)束了對(duì)這個(gè)生成器的迭代過程。

這四者之間的關(guān)系可能會(huì)稍微有些混亂,再給大家簡(jiǎn)單的總結(jié)一下:生成器是一種特殊的迭代器,而迭代器又是一種特殊的可迭代對(duì)象,可迭代對(duì)象就是可以執(zhí)行迭代操作也就是可以通過for循環(huán)來(lái)遍歷的對(duì)象。


2. 為什么要使用yield

看了上述兩個(gè)迭代過程,大家可能有些疑問,使用yield改造成生成器方式的代碼看起來(lái)比簡(jiǎn)單的迭代一個(gè)列表的方式要復(fù)雜許多,那么這樣寫有什么優(yōu)勢(shì)呢?

首先,使用yield語(yǔ)法的生成器最主要的一個(gè)優(yōu)勢(shì)就是極其省內(nèi)存。例如上述兩個(gè)迭代過程,同樣是遍歷輸出0-4這幾個(gè)元素,使用列表的方式需要構(gòu)建出一個(gè)長(zhǎng)度為5的數(shù)組并存儲(chǔ)在內(nèi)存中,而使用生成器的方式只需要一個(gè)index變量即可實(shí)現(xiàn),這還是迭代元素較少的情況下,如果迭代的是100萬(wàn)甚至1000萬(wàn)個(gè)元素時(shí),列表的方式就需要構(gòu)建一個(gè)長(zhǎng)度為100萬(wàn)或者1000萬(wàn)的數(shù)組,這時(shí)對(duì)于內(nèi)存的使用就是非常大的負(fù)擔(dān)了,而使用生成器的方式,無(wú)論是迭代100萬(wàn)還是1000萬(wàn)個(gè)元素,依然只需要一個(gè)index變量即可實(shí)現(xiàn)。

并且生成器的方式是即用即計(jì)算的,即迭代到對(duì)應(yīng)的元素時(shí),這個(gè)元素才相應(yīng)的計(jì)算生成出來(lái),而列表的方式需要在迭代開始前就構(gòu)建出整個(gè)迭代數(shù)組,這在某些情況下可以極大地節(jié)省計(jì)算時(shí)間。例如下面這段代碼:

.在學(xué)習(xí)中有迷茫不知如何學(xué)習(xí)的朋友小編推薦一個(gè)學(xué)Python的學(xué)習(xí)q u n? ?227? -435-? 450可以來(lái)了解一起進(jìn)步一起學(xué)習(xí)!免費(fèi)分享視頻資料

這段代碼中,實(shí)際的迭代過程只進(jìn)行到第10個(gè)元素即退出了整個(gè)循環(huán),但是在迭代開始前,依然要計(jì)算1000萬(wàn)次來(lái)生成迭代列表,這就造成了大量的計(jì)算和內(nèi)存資源。而如果通過生成器重寫該迭代過程的話:

生成器在迭代開始前并不會(huì)計(jì)算出所有需要迭代的值,只有用到時(shí)才會(huì)計(jì)算相應(yīng)的值并返回,因此上述代碼的index將只會(huì)計(jì)算到10即結(jié)束了整個(gè)迭代過程,避免了計(jì)算和內(nèi)存資源的浪費(fèi)。

3. yield語(yǔ)法示例1:DIY一個(gè)range函數(shù)

Python自帶的range函數(shù)可以產(chǎn)生一個(gè)可迭代對(duì)象,常用于for循環(huán)中,在Python 2中range函數(shù)生成的是一個(gè)列表,而在Python 3中range函數(shù)生成的是一個(gè)生成器?,F(xiàn)在讓我們來(lái)通過yield語(yǔ)法DIY一個(gè)自己的range生成器吧!

我們首先構(gòu)造一個(gè)返回給定范圍數(shù)組的函數(shù):

這個(gè)函數(shù)接受兩個(gè)int類型的參數(shù),分別為數(shù)組的開始和結(jié)束,每個(gè)數(shù)之間間隔為1,我們還可以通過增加一個(gè)參數(shù)來(lái)指定兩個(gè)數(shù)之間的間隔,實(shí)現(xiàn)函數(shù)更高的靈活性:

我們先來(lái)運(yùn)行測(cè)試一下這個(gè)range函數(shù):

上述代碼的輸出結(jié)果如下:

2

4

6

輸出結(jié)果符合我們的預(yù)期,現(xiàn)在通過yield語(yǔ)法來(lái)將我們自己DIY的range函數(shù)改造成一個(gè)生成器:

改造起來(lái)也非常簡(jiǎn)單,首先將定義的用來(lái)存儲(chǔ)迭代元素的列表刪除,然后將原來(lái)添加元素到列表中的代碼改造成yield start即可,這樣我們就自己DIY了一個(gè)簡(jiǎn)易的、基于生成器實(shí)現(xiàn)的range函數(shù)。

4. yield語(yǔ)法示例2:讀取文件--《告白氣球》

生成器除了可以用于計(jì)算生成數(shù)字元素外,在IO讀取方面也能起到很大作用,例如在讀取一個(gè)超大文件,或者查詢某個(gè)返回結(jié)果超多的數(shù)據(jù)庫(kù)時(shí),使用通過yield語(yǔ)法構(gòu)造的生成器來(lái)完成讀取操作可以很大程度上降低程序?qū)τ趦?nèi)存的占用。

例如我們有一個(gè)名為my_file.txt的文件,里面存儲(chǔ)了周董的《告白氣球》的歌詞,現(xiàn)在我們可以通過yield語(yǔ)法來(lái)構(gòu)造一個(gè)生成器用于一行一行的讀取每一句歌詞:

這里使用with語(yǔ)法來(lái)讀取文件,這是Python 3推薦的方式。file.readline()函數(shù)每次返回一行內(nèi)容,由于返回的內(nèi)容帶有每行結(jié)尾的換行符,因此通過line.strip(‘ ’)將換行符過濾掉。每次通過yield返回一行內(nèi)容之后,再次通過file.readline()函數(shù)獲取下一行內(nèi)容,直到整個(gè)文件被完全迭代。

讓我們來(lái)運(yùn)行測(cè)試一下這個(gè)按行讀取文件內(nèi)容的生成器:

上述代碼的輸出結(jié)果如下:

塞納河畔 左岸的咖啡

我手一杯 品嘗你的美

留下唇印 的嘴

……

《告白氣球》的歌詞就一行一行的輸出到屏幕上了,由于歌詞行數(shù)過多,因此這邊只復(fù)制出前三行給大家演示結(jié)果。

5. yield語(yǔ)法示例3:斐波那契數(shù)列

斐波那契數(shù)列是一道經(jīng)典的算法題,也是程序員面試時(shí)經(jīng)常會(huì)被問到的一道題。斐波那契數(shù)列的就是一個(gè)形如1, 1, 2, 3, 5, 8, ……的數(shù)列,從第三項(xiàng)開始,每一項(xiàng)都等于前兩項(xiàng)之和。使用Python來(lái)實(shí)現(xiàn)一個(gè)計(jì)算斐波那契數(shù)列的典型函數(shù)如下:

這個(gè)函數(shù)通過一個(gè)名為fib_list的數(shù)組存儲(chǔ)生成的前n個(gè)斐波那契數(shù),最后一次性返回整個(gè)數(shù)組。其中a, b = b, a + b是Python的一個(gè)特色用法,用于快速交換兩個(gè)數(shù),相當(dāng)于:

參考之前DIY的range函數(shù)的寫法,將這個(gè)計(jì)算斐波那契數(shù)列的函數(shù)通過yield語(yǔ)法修改為生成器:

讓我們來(lái)測(cè)試運(yùn)行一下這個(gè)通過yield語(yǔ)法實(shí)現(xiàn)的斐波那契數(shù)列生成器:

對(duì)應(yīng)的輸出結(jié)果為:

1

1

2

3

5

可以看到,從第三項(xiàng)開始的每一項(xiàng)都是前兩項(xiàng)的和,這樣的輸出結(jié)果就是我們要的斐波那契數(shù)列。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 什么是yield 在介紹yield語(yǔ)法之前,首先要向大家說(shuō)明Python中的迭代(iteration)、可迭...
    妄心xyx閱讀 1,566評(píng)論 0 76
  • 迭代、迭代器、生成器、協(xié)程、yield、greenlet、gevent、進(jìn)程線程協(xié)程對(duì)比、gevent多任務(wù)圖片下...
    Cestine閱讀 533評(píng)論 0 0
  • 包(lib)、模塊(module) 在Python中,存在包和模塊兩個(gè)常見概念。 模塊:編寫Python代碼的py...
    清清子衿木子水心閱讀 3,914評(píng)論 0 27
  • 文/君陌【來(lái)自清韻】 圖/網(wǎng)絡(luò) ? 阡夜與阡淵立下生死協(xié)議的時(shí)候,在雪泣山的深處有四個(gè)頭發(fā)花白的老頭在池塘邊垂釣。...
    清韻難敲閱讀 288評(píng)論 0 1
  • Spring Cloud Consul項(xiàng)目是針對(duì)Consul的服務(wù)治理實(shí)現(xiàn)。Consul是一個(gè)分布式高可用的系統(tǒng),...
    i_cyy閱讀 631評(píng)論 0 0

友情鏈接更多精彩內(nèi)容