$tree acme/ acme/ ├───acme │ ├───__init__.py │ └───sql │ └──__init__.py └───setup.py 2 directories, 3 files在此基礎上,如果想新增一個新的子包,例如新增 templating,則需要將其包含在 acme 的原始碼樹中,如下所示:
$tree acme/ acme/ ├───acme │ ├───__init__.py │ ├───sql │ │ └──__init__.py │ └───templating │ └──__init__.py └───setup.py 3 directories, 4 files仔細觀察就會發現,採用這種方式幾乎不可能單獨開發 acme.sql 和 acme.templating。且 setup.py 指令碼還必須指定每個子包的所有依賴,所以不可能(至少非常困難)選擇性地安裝 acme 中的部分元件。此外,如果某些子包的需求檔案有衝突,是一個無法解決的問題。
$tree acme.sql/ acme.sql/ ├───acme │ └───sql │ └──__init__.py └───setup.py 2 directories, 2 files $tree acme.templating/ acme.templating/ ├───acme │ └───templating │ └──__init__.py └───setup.py 2 directories, 2 files由此,就可以在 PyPI 或者使用的任何包索引中單獨註冊它們,使用者還可以從 acme 名稱空間中選擇想要安裝的子包,而無需安裝通用的 acme 包,執行程式碼如下:
$pip install acme.sql acme.templating
注意,獨立的原始碼樹不足以在 Python 中建立名稱空間包,如果不想讓包之間相互覆蓋,就需要做一些額外的工作,此外,正確的處理方式也會隨著 Python 版本的不同而有所不同。from setuptools import setup setup( name = 'acme.templating', packages = ['acme.templating'], )但是,直到發表本節時,setuptools.find_packages() 還不支援 PEP 420,但這在未來很可能會改變。此外,要想實現名稱空間包的簡單繼承,顯示地定義包列表是值得的。
$tree acme.sql/ acme.sql/ ├───acme │ ├──__init__.py │ └───sql │ └──__init__.py └───setup.py 2 directories, 3 files $tree acme.templating/ acme.templating/ ├───acme │ ├──__init__.py │ └───templating │ └──__init__.py └───setup.py 2 directories, 3 files注意,acme.sql 和 acme.templating 都有一個額外的原始碼檔案 acme/__init__.py,這個檔案必須是空的。
from setuptools import setup setup( name = 'acme.templating', packages = ['acme.templating'], namespace_package = ['acme'], )當然,最簡單的方法不一定是最好的,為了註冊一個新的名稱空間,setuptools 將會在 __init__.py 檔案中呼叫 pkg_resources.declare_namespace() 函數,即便 __init__.py 檔案是空的也會呼叫。
__import__('pkg_resources').declare_namespace(__name__)