面試必備|帶你徹底搞懂Python生成器
2019年人工智慧系統學:
https://edu.csdn.net/topic/ai30?utm_source=ai100_bw
作者 | Rocky0429
轉載自 Python空間(ID:Devtogether)
寫在之前
Python 的高階語言特性一直是我們學習 Python 的一個難點,大部分人並沒有做到熟練的掌握,甚至去學習它都感覺很困難,「生成器」作為其中甚是有用的特性之一,更是如此。
因為在其它的主流語言(C/C++/JAVA)中並沒有生成器的概念,加之其具有一定的難度,學習起來花費的時間成本較大,很多人自我安慰式的視其為“雞肋”,然後果斷放棄如此有用的一個高階語言特性,實在是一件很惋惜的事情。
其實不光是對於「生成器」而言,對於其它的高階語言特性還是建議大家要花點時間去搞懂的,不說其它,這些東西作為面試中常考的內容也應該引起你的重視,畢竟公司不是傻瓜,沒有用的東西幹嘛要考你?
接下來就讓我們來一起學習「生成器」,我儘量用大家都聽的懂的話,層層遞進的講解,保證大家都能看懂,前提是要有耐心,文章較長,建議先收藏再看。
答應我,一定要有耐心。
迭代器
在這說「迭代器」的原因是「生成器」自動實現了「迭代器協議」,所謂協議,就是一種約定。為了更好的理解生成器,我們需要簡單知道一下「迭代器協議」到底是個什麼東西。其實只需要滿足兩個兩個條件:1.實現 __iter__ 方法;2.物件實現 next() 方法,要麼返回迭代中的下一項,要麼就是以 StopIteration 異常終止迭代。
物件就是「可迭代物件」,即實現了迭代器協議的物件,它實現了迭代器協議。其實像是 Python 中 for 迴圈,sum 函式等等就是使用迭代器協議訪問物件。
你可能看著有點懵,怎麼又是「迭代」又是「迭代器」又是「可迭代物件」的,這對大家來說是很抽象的概念,但是不用怕,我在很久之前的文章中,已經很詳細的介紹過這倆哥們,你只需要點選下面的連結去看就好了,這也是面試中常見的問題哦:
生成器
如果你理解了上一節的內容,那麼恭喜你,接下來學習「生成器」就會簡單很多。Python 使用生成器對「延遲操作」提供了支援,所謂「延遲操作」就是在需要它的時候才產生結果,而不是說立即產生結果。
首先我們先來看一個入門級別的版本,你只需要點選下面的連結即可:
接下來講的相當於是上面文章的一個延伸和再擴充。
Python 其實有兩種不同的方法來提供生成器,一種是函式形式,另一種是表示式形式,說全一點兒就是「生成器函式」和「生成器表示式」。
1.生成器函式
「生成器函式」和普通的函式定義類似。區別在於普通函式使用 return 返回結果,生成器函式是用 yield 返回結果。
yield 的作用是在呼叫的時候返回相應的值,一次返回一個結果,在每個結果中間掛起函式的狀態(即暫停執行),下一次執行是從上次暫停的位置開始,繼續向下執行。
下面我們來做一道題,要求寫出「將一個全是整數的列表進行操作後只保留奇數」。相信大多數人都能很快的寫出下面這樣的函式:
def get_odd(lst):
res = []
for i in lst:
if i % 2:
res.append(i)
return res
def main():
lst = range(10)
for i in get_odd(lst):
print(i)
if __name__ == '__main__':
main()
上面這個沒什麼難度,既然我們學了「生成器」,我在前面還這麼舔它,是不是我們該用生成器來做一下這道題?看看用生成器來做同樣的功能,到底有什麼不同:
def get_odd(lst):
for i in lst:
if i % 2:
yield i
def main():
lst = range(10)
for i in get_odd(lst):
print(i)
if __name__ == '__main__':
main()
對比一下這個功能的兩種做法,使用「生成器」以後,程式碼變的行數更少了(省去了對 res 的操作,不用把結果存在 res 裡),程式碼整體看起來更清晰了(一看就知道幹嘛的,不用一上來去想 res 是個什麼鬼,append 進去的是個什麼玩意兒)。
2.生成器表示式
「生成器表示式」和列表推導式類似。區別在於使用列表推導,一次會產生所有的結果,而用「生成器表示式」則不會這樣,它是按需產生。
列表推導式的寫法如下:
>>> res = [x for x in range(5)]
>>> res
[0, 1, 2, 3, 4]
生成器表示式就是將上面的 [] 變成 () 即可:
>>> res = (x for x in range(5))
>>> res
<generator object <genexpr> at 0x109d9f570>
>>> next(res)
0
>>> next(res)
1
>>> next(res)
2
>>> next(res)
3
我們也順便簡單的看一下「生成器」的優勢在「生成器表示式」中是怎麼體現的。如果我們想對一系列整數求和,直接用生成器可以寫成下面這樣:
>>> sum((x for x in range(5)))
10
當然為了方便起見,也可以省略圓括號,即寫成下面這樣:
>>> sum(x for x in range(5))
10
但是如果你用常規的寫法去寫,就會寫成下面這樣:
>>> sum([x for x in range(5)])
10
上面的程式碼先構造了一個列表,然後再用 sum 函式求和,多了一步,天差地別,光在時間效率上,就已經輸掉了褲子。
所以綜合上面文章所講,「生成器」光在明面上的優點就有好幾個:程式碼行數更少;程式碼更易讀;時效更高...
所以,你還敢視它為“雞肋”嗎?
60s測試:你是否適合轉型人工智慧?
https://edu.csdn.net/topic/ai30?utm_source=ai100_bw
(本文為 AI科技大本營轉載文章,轉載請微信聯絡原作者)
群招募
掃碼新增小助手微信,回覆:公司+研究方向(學校+研究方向),邀你加入技術交流群。技術群稽核較嚴,敬請諒解。
推薦閱讀:
點選“閱讀原文”,檢視歷史精彩文章。
相關文章
- 看完讓你徹底搞懂Websocket原理Web
- 徹底搞懂徹底搞懂事件驅動模型 - Reactor事件模型React
- 徹底搞懂Python中的類Python
- 徹底搞懂 RxJavaRxJava
- 帶你徹底弄懂Event LoopOOP
- 徹底搞懂 python 中文亂碼問題Python
- 徹底搞懂https原理HTTP
- 徹底搞懂JavaScript作用域JavaScript
- 徹底搞懂Bean載入Bean
- 徹底搞懂 Git-RebaseGit
- 徹底搞懂Python 中的 import 與 from importPythonImport
- 一文徹底搞懂Python可迭代(Iterable)、迭代器(Iterator)和生成器(Generator)的概念Python
- 一文徹底搞懂面試中常問的各種“鎖”面試
- 深入JavaScript系列(四):徹底搞懂thisJavaScript
- 徹底搞懂 Channel 實現原理
- 徹底搞懂 RxJava — 基礎篇RxJava
- 徹底搞懂 RxJava — 中級篇RxJava
- 徹底搞懂 RxJava — 高階篇RxJava
- 面試都在問的微服務、服務治理、RPC、下一代微服務... 一文帶你徹底搞懂!面試微服務RPC
- 乾貨預警,一篇文章帶你徹底搞懂 Laravel 框架的執行原理!!!Laravel框架
- 徹底搞懂JavaScript中的繼承JavaScript繼承
- 兩萬字長文,徹底搞懂Kafka!Kafka
- 徹底搞懂JavaScript原型和原型鏈JavaScript原型
- 高頻面試題:一張圖徹底搞懂Spring迴圈依賴面試題Spring
- 徹底搞懂Redis持久化機制,輕鬆應對工作面試Redis持久化面試
- Java的程式設計思想太抽象?3小時帶你徹底搞懂!(附思維導圖)Java程式設計抽象
- 一文帶你徹底理解 JavaScript 原型物件JavaScript原型物件
- 一題帶你徹底理解sleep()和wait()AI
- 12張圖帶你徹底理解分散式事務!!分散式
- 徹底搞懂原型、原型鏈和繼承原型繼承
- 從原理到實戰,徹底搞懂NginxNginx
- Flutter(五)之徹底搞懂Dart非同步FlutterDart非同步
- 徹底搞懂瀏覽器Event-loop瀏覽器OOP
- 徹底搞懂Scrapy的中介軟體(三)
- 徹底搞懂Scrapy的中介軟體(二)
- 徹底搞懂Scrapy的中介軟體(一)
- 徹底搞懂HTTPS的加密機制HTTP加密
- 徹底搞懂Object和Function的關係ObjectFunction