繁体   English   中英

在Python中创建命名空间包的方法

[英]The way to make namespace packages in Python

分布式的命名空间包中 ,我知道我可以利用命名空间包将一个大的Python包分成几个较小的包。 真的很棒。 该文件还提到:

顺便提一下,请注意,在正常的Python包布局中,项目的源树必须包含命名空间包'__init__.py文件(以及任何父包的__init__.py)。 这些__init__ .py文件必须包含以下行:

 __import__('pkg_resources').declare_namespace(__name__) 

此代码确保命名空间包机制正在运行,并且当前包已注册为命名空间包。

我想知道将相同的目录层次结构保存到包的层次结构有什么好处吗? 或者,这只是distribute / setuptools的命名空间包功能的技术要求?

当然,

我想提供一个子包foo.bar ,这样我就必须构建以下文件夹层次结构并准备__init__.py以使setup.py工作在命名空间包中:

~foo.bar/
~foo.bar/setup.py
~foo.bar/foo/__init__.py    <=    one-lined file dedicated to namespace packages
~foo.bar/foo/bar/__init__.py
~foo.bar/foo/bar/foobar.py

我不熟悉命名空间包,但它在我看来1)foo / bar和2)(几乎)单行__init__.py是例行任务。 它们确实提供了一些“这是命名空间包”的提示,但我认为我们已经在setup.py中提供了这些信息?

编辑:

如下面的块所示,我可以在我的工作目录中使用没有该嵌套目录和单行__init__.py的命名空间包吗? 也就是说,我们可以通过只设置一行namespace_packages = ['foo']来请求setup.py自动生成这些吗?

~foo.bar/
~foo.bar/setup.py
~foo.bar/src/__init__.py    <=    for bar package
~foo.bar/src/foobar.py

在导入子包时,命名空间包主要具有特定的效果。 基本上,这是导入foo.bar时发生的情况

  • 导入器扫描sys.path ,查找看起来像foo东西。
  • 当它找到某些东西时,它会看到发现的foo里面的bar
  • 如果没有找到bar
    1. 如果foo是普通包,则会引发ImportError ,表明foo.bar不存在。
    2. 如果foo命名空间包,则导入器会返回查看sys.path以查找foo的下一个匹配项。 只有在所有路径都已耗尽时才会引发ImportError

这就是它的作用 ,但并没有解释为什么你会这么想。 假设你设计了一个很大的,有用的库( foo ),但作为其中的一部分,你还开发了一个小但非常有用的实用程序( foo.bar ),其他python程序员发现它很有用,即使它们没有用于更大的图书馆

您可以将它们一起分发为一个包的大块(就像您设计的那样),即使大多数使用它的人只会导入子模块。 你的用户会发现这非常不方便,因为他们必须下载整个东西(所有200MB!),即使他们真的只对10行实用程序类感兴趣。 如果你有一个开放的许可证,你可能会发现有几个人最终要求它,现在你的实用程序模块有六个不同版本。

您可以重写整个库,以便实用程序位于foo命名空间之外(只是bar而不是foo.bar )。 您将能够单独分发该实用程序,并且您的一些用户会很高兴,但这是很多工作,特别是考虑到实际上很多用户使用整个库,因此他们将不得不重写他们的程序使用新的。

所以你真正想要的是一种foo.bar安装foo.bar的方法,但是当你想要的时候也很乐意与foo共存。

命名空间包允许这两个完全独立的foo包安装可以共存。 setuptools会认识到这两个包被设计成彼此相邻并礼貌地移动文件夹/文件,使得它们都在路径上并显示为foo ,一个包含foo.bar而另一个包含其余的foo

你将有两个不同的setup.py脚本,每个脚本一个。 两个包中的foo/__init__.py必须指示它们是命名空间包,因此无论首先发现哪个包,导入器都知道继续。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM