虽然已经晚了,但帮助Python中的同行走过名称空间路径从未错过!
#1:
使用 __init__.py
,我应该使用哪个(如果有)?:
这取决于你的需求,以下是三种做名称空间包的方法 here:
使用本地名称空间包。此类型的名称空间包在PEP 420中定义,适用于Python 3.3及更高版本。如果您的命名空间中的包仅需要支持 Python 3,并通过 pip 进行安装,则建议使用此方法。
使用 pkgutil 样式的名称空间包。这适用于需要支持Python 2和3以及通过pip和python setup.py install进行安装的新软件包。
使用 pkg_resources 样式的名称空间包。如果您需要与已使用此方法的软件包兼容或者您的包需要是 zip 安全的,则建议使用此方法。
如果您使用 #2 (pkgutil-style
) 或 #3 (pkg_resources-style
),那么您将不得不使用相应风格的 __init__.py
文件。如果您使用本地名称空间,则不需要在名称空间目录中使用 __init__.py
。
#2:
使用setup.py时,我是否仍需要添加namespace_modules参数?如果需要,我应该使用namespace_modules=['org.common']还是namespace_modules=['org','common']?
如果您选择的命名空间包不是本地样式,则需要在您的setup()中使用namespace_packages。
#3:
我是否可以通过以某种不同的方式实现来放弃上述所有内容?也许有更简单或更“Pythonic”的方法吗?
由于您最终涉及到Python中的一个复杂主题,因此似乎您知道自己在做什么,想要什么并确定创建Python Namespace包是解决问题的方法。这被认为是解决问题的一种Pythonic方式。
除了您提出的问题,我还发现了一些事情:
我阅读了PEP420、Python Packaging guide并花了很多时间理解命名空间包,我通常了解它是如何工作的。我阅读了几个答案here、here、here以及SO上的这个帖子-这里和Rob分享的Git link上的示例。
然而,我的问题是在我创建包后。由于所有的说明和示例代码都明确列出了包在setuptools.setup(package=[])
函数中,我的代码失败了。我的子包/目录没有被包含。深入挖掘后,我发现setuptools有一个find_namespace_package()
函数,可以帮助添加子包。
编辑:
链接到find_namespace_packages()
(setuptools
版本大于40.1.0
): https://setuptools.readthedocs.io/en/latest/setuptools.html#find-namespace-packages
编辑(08/09/2019):
为了完整回答,让我举个例子来重构一下。
以下解决方案假定使用支持隐式命名空间包的Python 3.3+
由于您正在寻找Python版本3.5
或更高版本的解决方案,请采用提供的代码示例并进一步阐述。
让我们假设以下内容:
命名空间/Python包名称:org
分发包:org_client
,org_common
Python:3.3+
setuptools:40.1.0
为了完成以下操作
from org.client.client1 import mod1
from org.common import config
保持顶级目录不变,即
org_client_client1_mod1
和
org_common_config
,您可以将结构更改为以下内容:
存储库1:
org_client_client1_mod1/
setup.py
org/
client/
client1/
__init__.py
submod1/
__init__.py
mod1/
__init__.py
somefile.py
file1.py
更新了setup.py
文件
from setuptools import find_namespace_packages, setup
setup(
name="org_client",
...
packages=find_namespace_packages(),
...
)
第二个代码仓库:
org_common_config/
setup.py
org/
common/
__init__.py
config/
__init__.py
someotherfile.py
更新了 setup.py
文件:
from setuptools import find_namespace_packages, setup
setup(
name="org_common",
...
packages=find_namespace_packages(),
...
)
安装(使用pip
):
(venv) $ pip3 install org_common_config/
(venv) $ pip3 install org_client_client1_mod1/
更新后的pip列表将显示以下内容:
(venv) $ pip3 list
...
org_client
org_common
...
但是它们不可导入,要导入它们,您需要遵循
org.client
和
org.common
符号表示法。
要了解原因,您可以在此处浏览(假设在venv内部):
(venv) $ cd venv/lib/python3.5/site-packages/
(venv) $ ls -l | grep org
你会发现没有org_client
或org_common
目录,它们被解释为命名空间包。
(venv) $ cd venv/lib/python3.5/site-packages/org/
(venv) $ ls -l
client/
common/
...
__init__.py
。 - user2357112setup.py
中。 - Bobby