您的位置:首頁>正文

Python3.7中一種懶載入的方式

Python部落組織翻譯, 歡迎轉發, 禁止轉載

注意:這篇博文中的代碼, 現在已經是PyPI上modutil模組的一部分了。

Python3.7在模組上也添加了__getattr__和__dir__兩個方法。 這個新特性讓我們能夠實現一些有趣的事情。 例如, 通過定義__dir__方法, 你可以要求dir(模組)只顯示__all__中定義的內容了。

但對於我來說, 我更關心__getattr__方法, 以及我如何能利用這個特性實現懶載入。 在本文的開始, 我希望先告訴大家, 大多數人的代碼是不需要懶載入的。 只有當懶載入帶來的好處很有用時你才應該使用它, 比如, 一個執行時間很短的終端程式。 對於大多數人, 懶載入都是沒有必要的,

甚至是有害的, 它會讓你延後得知導入失敗, 而不是項目一啟動時就能夠知道。

舊方法

之前我們有兩種方式做懶載入。 最古老的方式是在局部載入, 而不是全域載入(例如在你定義的函數內進行導入, 而不是在模組頂部進行導入)。 這種方式確實推遲了載入的時間點, 在你的函數被運行時, 函數裡的import語句才會進行真正的載入。 但它有一個缺點就是, 這個import語句需要在不同的函數中寫很多次。 而且由於你只是在一些函數中寫了import語句, 你很可能寫著寫著就忘記了想要規避哪個模組的全域引用, 然後後面又不小心全域引用了同樣的模組。 這個做法確實能實現懶載入, 就是寫法不夠好。

另一種方法是使用importlib中提供的延遲載入器。

Google、Facebook和Mercurial的很多開發者在使用這個延遲載入器。 Google和Facebook主要是看中這個方法性能不錯, Mercurial主要是看中這個方法比較簡單、開發迅速。 使用這個延遲載入器有一個很好的效果, 它會提前檢查要導入的模組是否能找到, 如果找不到會拋出一個ModuleNotFoundError錯誤, 而真正被延遲的只是模組載入的過程。

很多人很喜歡這個延遲載入器, 以至於他們讓所有的東西都延遲載入了。 這樣做有優點也有缺點。 優點是你沒有額外付出什麼努力, 就讓所有的模組都延遲載入了。 缺點是因為你讓模組預設延遲載入了, 會導致一些需要即時載入的模組的邏輯發生錯誤(這也就是Python箴言中為什麼說明確優於隱晦)。 事實上, Mercurial為了避免這個問題,

專門維護了一個模組黑名單, 黑名單上的模組不進行延遲載入。 但為此, 他們不得不一直維護這個名單, 所以這樣做也不是一個很好的辦法。

新方法

在Python3.7中, 模組上可以定義一個__getattr__方法, 這讓開發者可以定義一個函數, 使得訪問的模組屬性不存在時, 導入一個模組作為當前模組的屬性。 這樣做確實也有“發現導入錯誤被推遲”這個弊病, 但是由於你的導入還是全域的, 所以代碼更容易控制。

這個代碼本身並不複雜。

你可以這樣使用上面的代碼

設計這個函數時, 最棘手的部分就是類比import ... as ... 語法來避免命名衝突, 我最終選擇使用一個類似原有as語法的字串。 我也可以把as語法字串再拆分為第三個參數, 這個參數也是一個字典物件, 但是我想沒必要這樣做, 能與原有語法有更多的相同點, 當然是最好的。

無論如何, 這個思考的過程都讓我很享受。 我喜歡這種用20行Python代碼就完成一個不錯的功能的感覺!

譯者:詩書塞外

英文原文:https://snarky.ca/lazy-importing-in-python-3-7/

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示