python - 如何在 Python 中创建命名空间包?

在 Python 中,命名空间包允许您在多个项目之间传播 Python 代码。当您想要将相关库作为单独的下载发布时,这很有用。例如,使用 PYTHONPATH 中的目录 Package-1Package-2

Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py

最终用户可以import namespace.module1import namespace.module2

定义一个命名空间包的最佳方式是什么,以便多个 Python 产品可以在该命名空间中定义模块?

最佳答案

TL;DR:

在 Python 3.3 上,您无需执行任何操作,只需不要将任何 __init__.py 放入您的命名空间包目录中,它就会正常工作。在 3.3 之前,选择 pkgutil.extend_path() 解决方案而不是 pkg_resources.declare_namespace() 解决方案,因为它是面向 future 的并且已经与隐式命名空间包兼容。


Python 3.3 引入了隐式命名空间包,见 PEP 420 .

这意味着现在可以通过 import foo 创建三种类型的对象:

  • foo.py 文件表示的模块
  • 一个常规包,由包含 __init__.py 文件的目录 foo 表示
  • 一个命名空间包,由一个或多个目录 foo 表示,没有任何 __init__.py 文件

包也是模块,但这里我说的“模块”是指“非包模块”。

首先它会扫描 sys.path 以查找模块或常规包。如果成功,它将停止搜索并创建和初始化模块或包。如果它没有找到模块或常规包,但它至少找到一个目录,它会创建并初始化一个命名空间包。

模块和常规包将 __file__ 设置为创建它们的 .py 文件。常规和命名空间包的 __path__设置为创建它们的目录。

当你执行 import foo.bar 时,上面的搜索首先发生在 foo,然后如果找到一个包,则搜索 bar 使用 foo.__path__ 作为搜索路径而不是 sys.path。如果找到 foo.bar,则创建并初始化 foofoo.bar

那么常规包和命名空间包是如何混合的呢?通常它们不会,但旧的 pkgutil 显式命名空间包方法已扩展为包含隐式命名空间包。

如果您有一个现有的常规包,其中包含这样的 __init__.py:

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

...遗留行为是将搜索到的路径上的任何其他常规包添加到其__path__。但在 Python 3.3 中,它还添加了命名空间包。

所以你可以有如下的目录结构:

├── path1
│   └── package
│       ├── __init__.py
│       └── foo.py
├── path2
│   └── package
│       └── bar.py
└── path3
    └── package
        ├── __init__.py
        └── baz.py

...只要两个 __init__.pyextend_path 行(和 path1path2path3 在你的 sys.path) import package.foo, import package.barimport package.baz 一切正常。

pkg_resources.declare_namespace(__name__) 尚未更新为包含隐式命名空间包。

https://stackoverflow.com/questions/1675734/

相关文章:

android - 如何在 Ubuntu 上安装 Android SDK?

linux - 在 Linux 中将多个 JPG 合并为单个 PDF

c - 如何在 Linux 上递归列出 C 中的目录?

python - 在 ipython 笔记本中测量单元执行时间的简单方法

linux - 在 shell 脚本中缩进多行输出

python - python的Maven等价物

linux - SO_REUSEADDR(setsockopt 选项)的含义是什么 - Linux?

mysql - 通过 shell 脚本使用 echo 命令自动化 mysql_secure_inst

linux - 在 Linux 的文本文件中用逗号替换空格

python - 如何跳过循环中的迭代?