迟到了,但在 Python 中帮助其他旅行者沿着命名空间路径走下去永远不会受到伤害!
#1:
使用__init__.py
,我应该使用哪些(如果有的话)?:
这取决于,这里列出了三种方法来执行命名空间包:
使用本机命名空间包。这种类型的命名空间包在 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']?
如果您选择的命名空间包不是原生样式,那么是的,您将需要namespace_packages
在setup()
.
#3:
我可以通过以某种不同的方式实现这一点来放弃上述所有内容吗?也许更简单或更“pythonic”的东西?
由于您最终在 python 中遇到了一个复杂的主题,因此您似乎知道自己在做什么,想要什么,并确定创建 Python 命名空间包是实现它的方法。这将被认为是解决问题的pythonic方法。
除了您的问题之外,我还发现了以下几点:
我阅读了 PEP420,Python 打包指南并花了很多时间来理解命名空间包,我大致了解它是如何工作的。我在这里、这里、这里阅读了几个答案,以及关于 SO 的这个线程——这里的示例和Rob 共享的 Git链接。
然而,我的问题是在我创建了我的包之后。由于所有说明和示例代码都明确列出了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
编辑(2019 年 8 月 9 日):
为了完成答案,让我也用一个例子进行重组。
以下解决方案假设 Python 3.3+ 支持隐式命名空间包
由于您正在寻找 Python 版本3.5
或更高版本的解决方案,让我们以提供的代码示例并进一步详细说明。
让我们假设以下内容:
命名空间/Python 包名:org
分发包:org_client
,org_common
Python:3.3+
设置工具: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(), # Follows similar lookup as find_packages()
...
)
存储库 2:
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(), # Follows similar lookup as find_packages()
...
)
要安装(使用pip
):
(venv) $ pip3 install org_common_config/
(venv) $ pip3 install org_client_client1_mod1/
更新的点子列表将显示以下内容:
(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
ororg_common
目录,它们被解释为命名空间包。
(venv) $ cd venv/lib/python3.5/site-packages/org/
(venv) $ ls -l
client/
common/
...