前言
你熟悉 Python/ target=_blank class=infotextkey>Python 中的 yield 關鍵字嗎?
你知道列表推導式與生成器推導式的區別嗎?
它們有什么使用場景?
假設有以下文本文件:
- 我們需要找到那些"目標" 開頭的行
你會怎么做?
一次把所有行讀取下來,然后遍歷過濾?
如果文件有100萬行呢?
同時輸出多個內容
如果我們把文件看作是一個倉庫,里面每一行是貨物。
你是零售商,此時有消費者找你買東西(那些"目標"開頭的貨物)
你有兩種方式。
方式1:
- 行5:你從倉庫中把所有的貨物搬到自己家里
- 行7-11:然后一份份過濾,找到那兩件貨物
辛不辛苦不知道,但是占空間是肯定,應該沒有誰會這么干吧
方式2:
- 行4-10:你本人走到倉庫里,逐一判斷扣下符合條件的貨物
此時解決了占家里空間的問題,但是你需要親自跑到倉庫做事情(代碼表現是你的判斷邏輯全混合到讀取文件邏輯中)
有沒有改進空間?
邏輯轉移
關鍵問題是:
- 紅色框是取貨邏輯,能不能移出來?
很簡單:
- 行8:遍歷過程中,都會調用一次 行15 我們提供的判斷邏輯
但是,這方式代碼實在不直觀,特別對比方式1:
- 讀取文件邏輯和取數判斷邏輯完全分開
如果可以這樣子就完美了:
- 注意,不能把所有的獲取一次性加載進來
數據生成器
其實,在上一種方式上簡單修改即可:
- 重點:不需要定義列表
- 行6:直接返回貨物,但是不用 return ,而是用 yield
此時,如果我們簡單調用這個函數,會得到什么?
- 這啥玩意
此時,這個函數叫做生成器(generator)。
注意,此時他根本不會加載數據,也就是說,這個函數里面的代碼根本沒有執行
它就像倉庫管理員,現在你不需要親自走進倉庫里面:
- 行3:這里做了2件事情,1是你打電話通知倉庫管理員準備。2是開始向他逐一拿出貨物
- 行4:你逐一篩選貨物
這里重點是叫他準備一次,他只能遍歷一次:
- 行1:做準備
- 行5:使用了之前的準備
- 行11:無法再用,此時 encore 啥也沒有
優點:
- 省了空間,整個過程中沒有一次性把所有數據加載進來
- 加載數據與處理數據的邏輯代碼獨立開來
- 代碼實際上比"邏輯轉移"的方式要多了一些,但是現在我們是用遍歷代碼表達,語義更加直觀清晰
需求升級一下:
在之前需求基礎下,把目標數值大于95的貨物取出來
想象一下,目標數量可能是200萬,上面的代碼行1變量 res 是一個列表,但數值大于95的可能只有幾行。
我們好像又遇到了之前的空間問題
生成器推導式
上一種方式得到的是列表,是因為我們使用了列表推導式,我們只需要簡單把最外層的方括號改為括號,推導式就會變成生成器:
- 行1 與 行5:使用括號,這是生成器推導式,并不會真正加載數據。所以不管數據有多少,這一句代碼都會瞬間執行完畢
你學會了沒有?
記得點贊,轉發!謝謝支持!