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

     2023-02-15     223

关键词:

【中文标题】如何在 Python 中创建命名空间包?【英文标题】:How do I create a namespace package in Python? 【发布时间】:2010-12-13 03:24:11 【问题描述】:

在 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 产品可以在该命名空间中定义模块?

【问题讨论】:

在我看来 module1 和 module2 实际上是子包而不是模块。据我了解,模块基本上是一个文件。也许 subpkg1 和 subpkg2 作为名称更有意义? 【参考方案1】:

TL;DR:

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


Python 3.3 引入了隐式命名空间包,请参阅PEP 420。

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

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

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

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

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

当您执行import foo.bar 时,上述搜索首先针对foo,然后如果找到一个包,则以foo.__path__ 作为搜索路径而不是sys.path 来搜索bar。如果找到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.fooimport package.bar 和@ 987654357@ 都可以。

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

【讨论】:

setuptools 怎么样?我必须使用namespace_packages 选项吗?还有__import__('pkg_resources').declare_namespace(__name__) 的事情? 我应该在setup.py 中添加namespace_packages=['package'] 吗? @clacke:使用namespace_packages=['package'],setup.py 将在EGG-INFO 中添加namespace_packages.txt。仍然不知道影响...... @kawing-chiu pkg_resources.declare_namespace 优于 pkgutil.extend_path 的好处是它将继续监视 sys.path。这样,如果在首次加载命名空间中的包之后将新项目添加到sys.path,则仍然能够加载该新路径项目中的命名空间中的包。 (使用__import__('pkg_resources') 而不是import pkg_resources 的一个好处是您最终不会将pkg_resources 暴露为my_namespace_pkg.pkg_resources。) @clacke 它不是那样工作的(但它的效果和它一样)。它维护使用该函数创建的所有包命名空间的全局列表,并监视sys.path。当sys.path 更改时,它会检查这是否会影响任何命名空间的__path__,如果是,则更新那些__path__ 属性。【参考方案2】:

有一个名为pkgutil 的标准模块,您可以使用它 可以将模块“附加”到给定的命名空间。

使用您提供的目录结构:

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

您应该将这两行放在Package-1/namespace/__init__.pyPackage-2/namespace/__init__.py (*) 中:

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

(* 因为 - 除非你声明它们之间的依赖关系 - 你不知道它们中的哪一个会首先被识别 - 请参阅 PEP 420 了解更多信息)

正如documentation 所说:

这将添加到包的__path__ 上以包命名的sys.path 目录的所有子目录。

从现在开始,你应该可以独立分发这两个包了。

【讨论】:

import__('pkg_resources').declare_namespace(__name) 相比,使用它的优缺点是什么? 首先,__import__ 在这种情况下被认为是不好的风格,因为它可以很容易地用简单的 import 语句替换。更重要的是,pkg_resources 是一个非标准库。它带有 setuptools,所以这不是问题。快速谷歌搜索显示 pkgutil 是在 2.5 中引入的,而 pkg_resources 早于它。尽管如此,pkgutil 是一个官方认可的解决方案。事实上,pkg_resources 包含在 PEP 365 中被拒绝。 来自PEP 382 的引用:当前命名空间包的命令式方法导致提供命名空间包的多个稍微不兼容的机制。例如,pkgutil 支持 *.pkg 文件; setuptools 没有。同样,setuptools 支持检查 zip 文件,并支持向其 _namespace_packages 变量添加部分,而 pkgutil 不支持。 是否应该将这两行放入两个文件中:Package-1/namespace/__init__.py Package-2/namespace/__init__.py,前提是我们不知道首先列出哪个包目录? @ChristofferKarlsson 是的,这就是重点,如果您知道哪个是第一个就可以了,但真正的问题是您能否保证它在任何情况下都会是第一个,即对于其他用户? 【参考方案3】:

This section should be pretty self-explanatory.

总之,把命名空间代码放在__init__.py,更新setup.py声明命名空间,就可以了。

【讨论】:

您应该始终引用链接的相关部分,以防相关链接失效。【参考方案4】:

这是一个老问题,但最近有人在我的博客上评论说我关于命名空间包的帖子仍然相关,所以我想我会在这里链接到它,因为它提供了一个如何实现它的实际示例:

https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb

链接到这篇文章的主要内容是:

http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package

__import__("pkg_resources").declare_namespace(__name__) 的技巧在很大程度上推动了TiddlyWeb 中插件的管理,到目前为止似乎正在奏效。

【讨论】:

siafoo 链接已损坏,这是存档副本的链接:web.archive.org/web/20200926015931/http://www.siafoo.net/…【参考方案5】:

你的 Python 命名空间概念是从头到尾的,在 python 中不可能将包放入模块中。包包含模块,而不是相反。

Python 包只是一个包含__init__.py 文件的文件夹。模块是包中(或直接在PYTHONPATH 上)具有.py 扩展名的任何其他文件。因此,在您的示例中,您有两个包,但没有定义模块。如果您认为包是文件系统文件夹而模块是文件,那么您就会明白为什么包包含模块而不是相反。

因此,在您的示例中,假设 Package-1 和 Package-2 是您放在 Python 路径上的文件系统上的文件夹,您可以拥有以下内容:

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

您现在拥有一个包namespace,其中包含两个模块module1module2。除非你有充分的理由,否则你可能应该将模块放在文件夹中,并且只在 python 路径中使用,如下所示:

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

【讨论】:

我说的是zope.x 之类的东西,其中一堆相关的软件包作为单独的下载发布。 好的,但是你想要达到的效果是什么。如果包含相关包的文件夹都在 PYTHONPATH 上,Python 解释器会为您找到它们,而无需您付出额外的努力。 如果您将 Package-1 和 Package-2 同时添加到 PYTHONPATH,Python 只会看到 Package-1/namespace/。

ReactiveMongoDatabase:如何预先创建集合:无法在多文档事务中创建命名空间

】ReactiveMongoDatabase:如何预先创建集合:无法在多文档事务中创建命名空间【英文标题】:ReactiveMongoDatabase:Howtocreatecollectionbeforehand:Cannotcreatenamespaceinmulti-documenttransaction【发布时间】:2020-06-3017:15:07【问题描述】:在我的@SpringBo... 查看详情

如何在c#中创建具有命名空间的文档

在有的XML文档中的tag和属性是带有分号的,例如xmlns:ua,ua:root等。这涉及不同的命名空间。在C#中需要特别的编程。网络上讲的稀里糊涂。这里记录了一些方法。例1//CreateanXMLtreeinanamespace.XNamespaceaw="http://www.adventure-works.co... 查看详情

如何在 dll 项目中的 C++ 中创建命名空间和构造函数?

】如何在dll项目中的C++中创建命名空间和构造函数?【英文标题】:Howdoicreateanamespaceandconstructorinc++inadllproject?【发布时间】:2013-04-2515:59:04【问题描述】:我在我的VisualStudio2012Pro上创建了一个新的dll项目,主.cpp文件是空的,除... 查看详情

Helm RBAC 规则在这些创建的名称中创建命名空间和资源

...时间】:2020-06-2722:18:16【问题描述】:我发现了很多关于如何授予helm权限以在特定命名空间中创建资源的信息。我正在尝试查看是否可以动态创建命名空间(使用随机名称),然后使用helm在命名空间内安装和删除资源。我的 查看详情

如何使用 RBAC API 在 Kubernetes 中创建受限于命名空间的用户/组?

】如何使用RBACAPI在Kubernetes中创建受限于命名空间的用户/组?【英文标题】:Howtocreateusers/groupsrestrictedtonamespaceinKubernetesusingRBACAPI?【发布时间】:2017-05-0915:07:30【问题描述】:问题我想向dev组内的许多不同的开发人员(不同的主... 查看详情

在 Python 中创建一个临时 FIFO(命名管道)?

...dpipe)inPython?【发布时间】:2010-11-2815:54:42【问题描述】:如何在Python中创建临时FIFO(命名管道)?这应该有效:importtempfiletemp_file_name=mktemp()os.mkfifo(temp_file_name)open(temp_file_name,os 查看详情

在 .NET 中创建 C++ ATL COM 嵌套命名空间,如 System 命名空间

】在.NET中创建C++ATLCOM嵌套命名空间,如System命名空间【英文标题】:CreateC++ATLCOMnestednamespaceslikeSystemnamespacein.NET【发布时间】:2012-10-3006:56:45【问题描述】:我有几个ATLCOM服务,并希望每个服务都有自己的命名空间,但位于一个... 查看详情

如何在c#中创建具有命名空间的文档

在有的XML文档中的tag和属性是带有分号的,例如xmlns:ua,ua:root等。这涉及不同的命名空间。在C#中需要特别的编程。网络上讲的稀里糊涂。这里记录了一些方法。例1//CreateanXMLtreeinanamespace.XNamespaceaw="http://www.adventure-works.co... 查看详情

xquery 转换在元素中创建空命名空间

】xquery转换在元素中创建空命名空间【英文标题】:xquerytransformationcreatesemptynamespaceinelement【发布时间】:2017-10-0309:41:51【问题描述】:我很抱歉,但我想我只是没有看到我在这里犯的错误。我有一个返回XML并能够测试输出的骆... 查看详情

在javascript中创建命名空间的几种写法

在JavaScript中创建命名空间的几种写法分享到分类 JS学习   关键字 JavaScript   发布 newghost  2014-06-03 注意 转载须保留原文链接,译文链接,作者译者等信息。  在JavaScript中全... 查看详情

在标头和源代码 (cpp) 中创建 C++ 命名空间

】在标头和源代码(cpp)中创建C++命名空间【英文标题】:CreatingaC++namespaceinheaderandsource(cpp)【发布时间】:2012-01-0221:36:16【问题描述】:在命名空间中包装头文件和cpp文件内容或仅包装头文件内容然后在cpp文件中执行usingnamespace有... 查看详情

根据包名,在指定空间中创建对象

根据包名,在指定空间中创建对象 输入描述:namespace({a:{test:1,b:2}},‘a.b.c.d‘)输出描述:{a:{test:1,b:{c:{d:{}}}}}functionnamespace(oNamespace,sPackage){varpackageArr=sPackage.split(‘.‘);varcurObj=oNamespace;//保留对原始对象的引用f 查看详情

在 Java DOM 中创建以命名空间为前缀的 XML 节点

】在JavaDOM中创建以命名空间为前缀的XML节点【英文标题】:CreatingnamespaceprefixedXMLnodesinJavaDOM【发布时间】:2015-04-1407:10:46【问题描述】:我正在通过Java创建几个XML文件,到目前为止一切正常,但现在我在尝试创建具有命名空间... 查看详情

根据包名,在指定空间中创建对象(代码片段)

描述: 根据包名,在指定空间中创建对象输入描述:namespace(a:test:1,b:2,\'a.b.c.d\')输出描述:a:test:1,b:c:d:1functionnamespace(oNamespace,sPackage)2varpackage=sPackage.split(\'.\');3varobj=oNamespace;4for(vari 查看详情

用户“system:anonymous”无法在命名空间“default”的 API 组“”中创建资源“pods”

...户“system:anonymous”无法在命名空间“default”的API组“”中创建资源“pods”【英文标题】:User"system:anonymous"cannotcreateresource"pods"inAPIgroup""inthenamespace"default"【发布时间】:2019-10-2209:27:14【问题描述】... 查看详情

为每个用户授予特定命名空间的权限

...我有很多用户。每个用户都应该能够在*-stage等命名空间中创建/更改/删除物质。命名空间可以动态添加或删除。我可以在每个命名空间中创建ServiceAccount并授予权限。我在k8s中创建了pod,并在其中安装了kubectl和s 查看详情

如何导入 Python 命名空间包的所有子模块?

】如何导入Python命名空间包的所有子模块?【英文标题】:HowdoIimportallthesubmodulesofaPythonnamespacepackage?【发布时间】:2012-05-2812:55:34【问题描述】:一个Python命名空间包可以分布在许多目录、zip文件或自定义导入器中。迭代命名空... 查看详情

如何使用 C++ 在 MongoDB 中创建地理空间索引

】如何使用C++在MongoDB中创建地理空间索引【英文标题】:HowtocreateGeoSpatialindexinMongoDBusingC++【发布时间】:2017-04-0719:10:57【问题描述】:在python/pymongo中,创建GeoSpatial索引非常简单:db.collection.create_index([("loc",GEO2D)],min=-100,max=100)... 查看详情