問題描述
在 Python 中,命名空間包允許您在多個項目之間傳播 Python 代碼.當您想要將相關庫作為單獨的下載發布時,這很有用.例如,使用 PYTHONPATH
中的目錄 Package-1
和 Package-2
,
In Python, a namespace package allows you to spread Python code among several projects. This is useful when you want to release related libraries as separate downloads. For example, with the directories Package-1
and Package-2
in PYTHONPATH
,
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
最終用戶可以import namespace.module1
和import namespace.module2
.
定義一個命名空間包的最佳方式是什么,以便多個 Python 產品可以在該命名空間中定義模塊?
What's the best way to define a namespace package so more than one Python product can define modules in that namespace?
推薦答案
TL;DR:
在 Python 3.3 上,您無需執行任何操作,只需不要將任何 __init__.py
放入您的命名空間包目錄中,它就會正常工作.在 3.3 之前,選擇 pkgutil.extend_path()
解決方案而不是 pkg_resources.declare_namespace()
解決方案,因為它是面向未來的并且已經與隱式命名空間包兼容.
On Python 3.3 you don't have to do anything, just don't put any __init__.py
in your namespace package directories and it will just work. On pre-3.3, choose the pkgutil.extend_path()
solution over the pkg_resources.declare_namespace()
one, because it's future-proof and already compatible with implicit namespace packages.
Python 3.3 引入了隱式命名空間包,請參閱 PEP 420.
Python 3.3 introduces implicit namespace packages, see PEP 420.
這意味著現在可以通過 import foo
創建三種類型的對象:
This means there are now three types of object that can be created by an import foo
:
- 由
foo.py
文件表示的模塊 - 一個常規包,由包含
__init__.py
文件的目錄foo
表示 - 一個命名空間包,由一個或多個目錄
foo
表示,沒有任何__init__.py
文件
- A module represented by a
foo.py
file - A regular package, represented by a directory
foo
containing an__init__.py
file - A namespace package, represented by one or more directories
foo
without any__init__.py
files
包也是模塊,但這里我說的模塊"是指非包模塊".
Packages are modules too, but here I mean "non-package module" when I say "module".
首先它會掃描 sys.path
以查找模塊或常規包.如果成功,它將停止搜索并創建和初始化模塊或包.如果它沒有找到模塊或常規包,但它至少找到一個目錄,它會創建并初始化一個命名空間包.
First it scans sys.path
for a module or regular package. If it succeeds, it stops searching and creates and initalizes the module or package. If it found no module or regular package, but it found at least one directory, it creates and initializes a namespace package.
模塊和常規包將 __file__
設置為創建它們的 .py
文件.常規和命名空間包的 __path__
設置為創建它們的目錄.
Modules and regular packages have __file__
set to the .py
file they were created from. Regular and namespace packages have __path__
set to the directory or directories they were created from.
當你執行 import foo.bar
時,上面的搜索首先發生在 foo
,然后如果找到一個包,則搜索 bar
使用 foo.__path__
作為搜索路徑而不是 sys.path
.如果找到 foo.bar
,則創建并初始化 foo
和 foo.bar
.
When you do import foo.bar
, the above search happens first for foo
, then if a package was found, the search for bar
is done with foo.__path__
as the search path instead of sys.path
. If foo.bar
is found, foo
and foo.bar
are created and initialized.
那么常規包和命名空間包是如何混合的呢?通常它們不會,但舊的 pkgutil
顯式命名空間包方法已擴展為包含隱式命名空間包.
So how do regular packages and namespace packages mix? Normally they don't, but the old pkgutil
explicit namespace package method has been extended to include implicit namespace packages.
如果您有一個現有的常規包,其中包含這樣的 __init__.py
:
If you have an existing regular package that has an __init__.py
like this:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
...遺留行為是將搜索到的路徑上的任何其他常規包添加到其__path__
.但在 Python 3.3 中,它還添加了命名空間包.
... the legacy behavior is to add any other regular packages on the searched path to its __path__
. But in Python 3.3, it also adds namespace packages.
所以你可以有如下的目錄結構:
So you can have the following directory structure:
├── path1
│?? └── package
│?? ├── __init__.py
│?? └── foo.py
├── path2
│?? └── package
│?? └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
...只要兩個 __init__.py
有 extend_path
行(和 path1
、path2
和 path3
在你的 sys.path
) import package.foo
, import package.bar
和 import package.baz
一切正常.
... and as long as the two __init__.py
have the extend_path
lines (and path1
, path2
and path3
are in your sys.path
) import package.foo
, import package.bar
and import package.baz
will all work.
pkg_resources.declare_namespace(__name__)
尚未更新為包含隱式命名空間包.
pkg_resources.declare_namespace(__name__)
has not been updated to include implicit namespace packages.
這篇關于如何在 Python 中創建命名空間包?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!