寫在之前
Python 的高級語言特性一直是我們學(xué)習(xí) Python 的一個難點,大部分人并沒有做到熟練的掌握,甚至去學(xué)習(xí)它都感覺很困難,「生成器」作為其中甚是有用的特性之一,更是如此。
因為在其它的主流語言(C/C++/JAVA)中并沒有生成器的概念,加之其具有一定的難度,學(xué)習(xí)起來花費的時間成本較大,很多人自我安慰式的視其為“雞肋”,然后果斷放棄如此有用的一個高級語言特性,實在是一件很惋惜的事情。
其實不光是對于「生成器」而言,對于其它的高級語言特性還是建議大家要花點時間去搞懂的,不說其它,這些東西作為面試中常考的內(nèi)容也應(yīng)該引起你的重視,畢竟公司不是傻瓜,沒有用的東西干嘛要考你?
接下來就讓我們來一起學(xué)習(xí)「生成器」,我盡量用大家都聽的懂的話,層層遞進的講解,保證大家都能看懂,前提是要有耐心,文章較長,建議先收藏再看。
答應(yīng)我,一定要有耐心。
迭代器
在這說「迭代器」的原因是「生成器」自動實現(xiàn)了「迭代器協(xié)議」,所謂協(xié)議,就是一種約定。為了更好的理解生成器,我們需要簡單知道一下「迭代器協(xié)議」到底是個什么東西。其實只需要滿足兩個兩個條件:1.實現(xiàn) __iter__ 方法;2.對象實現(xiàn) next() 方法,要么返回迭代中的下一項,要么就是以 StopIteration 異常終止迭代。
對象就是「可迭代對象」,即實現(xiàn)了迭代器協(xié)議的對象,它實現(xiàn)了迭代器協(xié)議。其實像是 Python 中 for 循環(huán),sum 函數(shù)等等就是使用迭代器協(xié)議訪問對象。
你可能看著有點懵,怎么又是「迭代」又是「迭代器」又是「可迭代對象」的,這對大家來說是很抽象的概念,但是不用怕,我在很久之前的文章中,已經(jīng)很詳細的介紹過這倆哥們,你只需要點擊下面的鏈接去看就好了,這也是面試中常見的問題哦:
零基礎(chǔ)學(xué)習(xí) Python 之初識迭代
Python 拓展之迭代器
生成器
如果你理解了上一節(jié)的內(nèi)容,那么恭喜你,接下來學(xué)習(xí)「生成器」就會簡單很多。Python 使用生成器對「延遲操作」提供了支持,所謂「延遲操作」就是在需要它的時候才產(chǎn)生結(jié)果,而不是說立即產(chǎn)生結(jié)果。
首先我們先來看一個入門級別的版本,你只需要點擊下面的鏈接即可:
零基礎(chǔ)學(xué)習(xí) Python 之初識生成器
接下來講的相當(dāng)于是上面文章的一個延伸和再拓展。
Python 其實有兩種不同的方法來提供生成器,一種是函數(shù)形式,另一種是表達式形式,說全一點兒就是「生成器函數(shù)」和「生成器表達式」。
1.生成器函數(shù)
「生成器函數(shù)」和普通的函數(shù)定義類似。區(qū)別在于普通函數(shù)使用 return 返回結(jié)果,生成器函數(shù)是用yield返回結(jié)果。
yield的作用是在調(diào)用的時候返回相應(yīng)的值,一次返回一個結(jié)果,在每個結(jié)果中間掛起函數(shù)的狀態(tài)(即暫停執(zhí)行),下一次執(zhí)行是從上次暫停的位置開始,繼續(xù)向下執(zhí)行。
下面我們來做一道題,要求寫出「將一個全是整數(shù)的列表進行操作后只保留奇數(shù)」。相信大多數(shù)人都能很快的寫出下面這樣的函數(shù):
defget_odd(lst): res = [] foriinlst: ifi %2: res.append(i) returnresdefmain(): lst = range(10) foriinget_odd(lst): print(i)if__name__ =='__main__': main()
上面這個沒什么難度,既然我們學(xué)了「生成器」,我在前面還這么舔它,是不是我們該用生成器來做一下這道題?看看用生成器來做同樣的功能,到底有什么不同:
defget_odd(lst): foriinlst: ifi %2: yieldidefmain(): lst = range(10) foriinget_odd(lst): print(i)if__name__ =='__main__': main()
對比一下這個功能的兩種做法,使用「生成器」以后,代碼變的行數(shù)更少了(省去了對 res 的操作,不用把結(jié)果存在 res 里),代碼整體看起來更清晰了(一看就知道干嘛的,不用一上來去想 res 是個什么鬼,append 進去的是個什么玩意兒)。
2.生成器表達式
「生成器表達式」和列表推導(dǎo)式類似。區(qū)別在于使用列表推導(dǎo),一次會產(chǎn)生所有的結(jié)果,而用「生成器表達式」則不會這樣,它是按需產(chǎn)生。
列表推導(dǎo)式的寫法如下:
>>> res = [xforxinrange(5)]>>> res[0, 1, 2, 3, 4]
生成器表達式就是將上面的 [] 變成 () 即可:
>>> res = (xforxinrange(5))>>> res
我們也順便簡單的看一下「生成器」的優(yōu)勢在「生成器表達式」中是怎么體現(xiàn)的。如果我們想對一系列整數(shù)求和,直接用生成器可以寫成下面這樣:
>>> sum((xforxinrange(5)))10
當(dāng)然為了方便起見,也可以省略圓括號,即寫成下面這樣:
>>> sum(xforxinrange(5))10
但是如果你用常規(guī)的寫法去寫,就會寫成下面這樣:
>>> sum([xforxinrange(5)])10
上面的代碼先構(gòu)造了一個列表,然后再用 sum 函數(shù)求和,多了一步,天差地別,光在時間效率上,就已經(jīng)輸?shù)袅搜澴印?/p>
所以綜合上面文章所講,「生成器」光在明面上的優(yōu)點就有好幾個:代碼行數(shù)更少;代碼更易讀;時效更高...
所以,你還敢視它為“雞肋”嗎?
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4346瀏覽量
62968 -
生成器
+關(guān)注
關(guān)注
7文章
319瀏覽量
21126 -
python
+關(guān)注
關(guān)注
56文章
4807瀏覽量
85037
原文標(biāo)題:面試必備|帶你徹底搞懂Python生成器
文章出處:【微信號:rgznai100,微信公眾號:rgznai100】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論