一日一技:如何實現高性能自動補全?
我們知道,在寫Python時,使用IDE的自動補全功能,可以大大提高代碼的開發效率。使用類型標注功能,可以讓IDE知道應該怎么做自動補全。
當我們沒有類型標注時,IDE并不知道函數的某個參數是什么東西,沒有辦法做補全,如下圖所示。
圖片
但當我們把類型標注加上以后,IDE就能正常補全了,如下圖所示:
圖片
這樣做,需要從另一個文件中,把這個參數對應的類導入到當前文件里面,然后把類作為類型填寫到函數參數后面。咋看起來沒有什么問題,并且我,還有很多看文章的同學,應該經常這樣寫類型標注的代碼,從而提高代碼的開發效率。
但如果你的項目規模大起來以后,你就會遇到幾個比較麻煩的問題:
- 導入鏈過長:例如上面截圖中的代碼,我從model.py中導入了Detail這個類。如果我在model.py文件的開頭,還有from aaa import bbb,而在aaa.py文件開頭,又有from ccc import ddd;在ccc.py開頭,又有from xxx import yyy……這個導入鏈條就會變得很長。雖然Python對模塊導入已經做了緩存,多次執行from xxx import yyy時,只有第一次會生效,后面都是讀取緩存,但讀取緩存也會消耗一些時間。
- 循環依賴:一般情況下,你的代碼能夠正常運行,那么應該是不會存在循環依賴的。否則肯定報錯了。但現在你在一個原來的依賴鏈條之外的文件中,為了做類型標注,導入了一個已有的文件。此時有可能就會引入循環依賴。特別是當代碼規模大起來以后,如果一開始沒有設計好代碼結構,稍不注意就會出現循環依賴。
如果你引入一個類,僅僅是為了做類型標注,那么這個問題實際上非常好解決。在Python的typing模塊里面,有一個常量,叫做TYPE_CHECKING,它就是為了解決這個問題而設計的。在你使用python xxx.py來啟動代碼時,TYPE_CHECKING的值是False。但當IDE的類型檢查或者Mypy這種靜態類型檢查工具運行時,TYPE_CHECKING的值是True。
因此,我們可以使用下面這段代碼,來提高代碼的運行效率,同時規避循環依賴的問題:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from xxx import YYY
def parse_detail(params: 'YYY'):
...
注意,在函數參數的類型標注里面,類YYY需要以字符串的形式寫出。如下圖所示:
圖片
使用這種方法,在寫代碼時,IDE能夠正確的做自動補全。在Mypy做靜態類型檢查時,也能過正常通過檢查。但當代碼實際運行時,會自動忽略這個導入的類,從而避免對代碼的運行效率造成影響。