如何在Python中创建名称空间包? [英] How do I create a namespace package in Python?

查看:140
本文介绍了如何在Python中创建名称空间包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Python中,命名空间包允许您在多个项目中传播Python代码.当您要将相关的库作为单独的下载发布时,这很有用.例如,对于PYTHONPATH中的目录Package-1Package-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.module1import 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,则会创建并初始化foofoo.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行(并且path1path2path3在您的sys.path中)import package.fooimport package.barimport 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆