命名空间与常规包

dar*_*ine 15 python package python-3.x

命名空间Python包(no __init__.py)和常规Python包(有__init__.py)之间的区别是什么,特别是当__init__.py常规包为空时?

我很好奇,因为最近我忘了制作__init__.py我制作的包装,我从来没有注意到任何问题.实际上,它们似乎与常规包装相同.

编辑:仅支持Python 3.3的命名空间包(参见PEP 420),所以很自然地,这个问题仅适用于Python 3.

Aar*_*all 14

命名空间包

命名空间包是一种特殊的包,允许您在Py​​thon路径的不同点统一两个具有相同名称的包.例如,将path1和path2视为Python路径上的单独条目:

path1
+--namespace
   +--module1.py
   +--module2.py
path2
+--namespace
   +--module3.py
   +--module4.py
Run Code Online (Sandbox Code Playgroud)

通过这种安排,您应该能够执行以下操作:

from namespace import module1, module3
Run Code Online (Sandbox Code Playgroud)

因此,您可以在单个命名空间中统一两个具有相同名称的包.如果任何人有一个__init__.py变成包-你不再得到统一为其他目录将被忽略.

__init__.py 曾经被要求使目录成为一个包

命名空间包是没有的包__init__.py.

有关简单包的示例,如果您有一个目录:

root
+--package
   +--file1.py
   +--file2.py
   ...
Run Code Online (Sandbox Code Playgroud)

虽然您可以在package目录中独立运行这些文件,例如with python file1.py,或者python3 file1.py,您将无法将文件作为模块导入根目录,例如

import module.file1
Run Code Online (Sandbox Code Playgroud)

会失败,为了让它起作用,你至少需要这个:

module
  +--__init__.py
  +--file1.py
  +--file2.py
  ...
Run Code Online (Sandbox Code Playgroud)

__init__.py初始化包,您可以在__init__.py首次导入模块时运行该代码,

run_initial_import_setup()
Run Code Online (Sandbox Code Playgroud)

提供__all__要导入的名称列表,

__all__ = ['star_import', 'only', 'these', 'names']
Run Code Online (Sandbox Code Playgroud)

如果使用以下内容导入:

from module import *
Run Code Online (Sandbox Code Playgroud)

或者,如果您只想导入目录中剩余的.py文件,则可以将其保留为空,但这是要求能够执行此操作.

命名空间:

您最初可以使用自Python 2.3以来可用的pkgutil.通过在每个单独的包中添加以下内容来完成添加命名空间__init__.py:

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
Run Code Online (Sandbox Code Playgroud)

Setuptools使用类似的方法,同样,所有__init__.py文件应包含以下内容(没有其他代码):

import pkg_resources
pkg_resources.declare_namespace(__name__)
Run Code Online (Sandbox Code Playgroud)

PEP 420中更彻底地解决了命名空间

另请参阅此处有关setuptools和命名空间的更多讨论:

http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages

  • @variable 感谢您让我注意到这一点,请查看它并让我知道您是否认为缺少任何内容? (2认同)

dar*_*ine 6

阅读Aaron 和PEP420的链接,似乎命名空间包和常规包之间的根本区别,除了常规包可能包含各种初始化代码的明显区别之外,命名空间包是一个虚拟包,其内容可以沿着Python的查找路径分布在各个地方。__init__.py

例如,给定

a/foo/bar.py
b/foo/baz.py
Run Code Online (Sandbox Code Playgroud)

如果 和ba在Python的路径中,则可以自由导入foo.barfoo.baz

当然,这引出了一个问题,如果__init__.py不需要,那么在其他条件相同的情况下,制作常规包还是命名空间包更好,但这有点偏离主题。