如何在Python中创建名称空间包? [英] How do I create a namespace package in Python?
问题描述
在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
,然后,如果找到了软件包,则以foo.__path__
作为搜索路径而不是sys.path
来进行bar
的搜索.如果找到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__
路径上添加任何其他 regular 软件包.但是在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中创建名称空间包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!