Python 中的__all__
隨著我們深入瞭解包和模組,我們可能會遇到設定在不同 _init_.py
檔案中的變數 __all__
。
__init__.py
檔案是使 Python 將目錄視為某些包含包的檔案。此檔案可防止具有相似名稱(例如字串)的目錄隱藏稍後可能出現在模組搜尋路徑上的有效模組。
在最簡單的情況下,__init__.py
可能是一個空檔案,但它也可能執行包的初始化程式碼或設定 __all__
變數。
因此,__init__.py
可以為包宣告 __all__
變數。
該模組的公共物件列表在 __all__
變數中給出。它由 import *
解析。此變數覆蓋了隱藏給定名稱空間中以下劃線開頭的所有內容的預設設定。
例如,
__all__ = ["a", "b"]
c = 5
a = 10
def b():
return "b"
現在我們在下面的程式碼中匯入它。
from sample import *
print(a) # will work fine
print(b) # will work fine
print(c) # will generate an error
在上面的例子中,我們使用 import *
將所有公共物件從檔案 sample.py
匯入到這個檔案中。這意味著該檔案將匯入並支援檔案 sample.py
的所有公共物件。
物件 a
和 b
將被匯入,新程式碼將在使用這些物件的地方完美執行。問題出現在使用第三個物件 c
時。該物件永遠不會匯入到新檔案中,因為它不是公共物件,也不是 __all__
變數的一部分。所以這部分程式碼會產生錯誤。
有一個替代方案。預設情況下,Python 將負責匯出所有不以下劃線 _
開頭的名稱。人們當然可以依賴這種機制。在 Python 標準庫中,一些包確實依賴於此,但為此,它們將它們的匯入別名化,例如,os
為 _os
,sys
為 _sys
等。
使用 _
約定更方便,因為它消除了重複命名名稱的冗餘。但它確實為匯入新增了冗餘(如果你有很多),並且更容易忘記始終如一地執行此操作。
標準庫中的很多包都使用 __all__
。當仍處於早期開發模式並且沒有使用者並且不斷調整你的 API 時,使用 _
字首約定代替 __all__
是有意義的。也許有一些使用者,但有一個覆蓋 API 的單元測試,並且仍在積極更新和新增 API,並在開發中進行調整。