python 包(多文件模块)的行为与一个大模块完全一样吗?

Posted

技术标签:

【中文标题】python 包(多文件模块)的行为与一个大模块完全一样吗?【英文标题】:Do python packages (multi-file modules) behave exactly as one big module? 【发布时间】:2011-01-24 11:06:38 【问题描述】:

我刚刚读到一篇文章,据说它向我介绍了一个新概念:到目前为止,我确信 python 包(即带有 __init__.py 文件的目录)的行为与 java 包完全相同,也就是说 - 很少命名空间来帮助安排代码(减去 java 的“包”范围)。 但是,根据这个链接: A Short Digression Into Multi-File Modules,如果我将所有文件放在同一个“包”中:

整个文件集合作为单个模块呈现给其他 Python 代码——就好像所有函数和类都在一个 .py 中一样

所以现在我认为我对 python“包”的整个理解是错误的。此外 - 它完全不是一个包,而是作者所说的“多文件模块”。

所以,据我了解,无论我在一个包中划分我的函数和类有多少个文件,从外部来看,该包应该看起来好像我从包内的所有文件中获取了所有代码并放入它而是在一个与包同名的大文件中,即作为一个模块。

例如,如果我有以下文件结构:

/base
    /animals
        /__init__.py
        /dog.py

在 dog.py 中:

def bark():
    print "woof"

它应该与拥有完全相同:

/base
    /animals.py

在animals.py中:

def bark():
    print 'woof'

因此,下一段代码在这两种情况下都应该运行良好:

from base import animals
animals.bark()

这当然会在第一种情况下产生:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'module' object has no attribute 'bark'

我在这里缺少什么?我看到“动物”确实被视为一个模块的例外情况,但似乎我仍然必须明确声明animals.dog.bark,即包的内部文件结构不是从外部抽象出来的。

我错过了作者的观点,还是没有正确实施?

=== 编辑 ===

只是为了确保没有人错过引用中的这一行:

好像所有的函数都在一个.py中

不管如何实际访问这个函数和类,上面的引用明确指出,如果你在文件 a 中有一个 func1,在文件 b 中有一个 func2,不管它们可以从哪个路径访问,如果我们将此路径表示为X 那么,根据上述引用,X.func1X.func2 都应该可以工作。

【问题讨论】:

我在链接页面上找不到该报价。想再试一次吗? @Ignacio: diveintopython3.org/… @ignacio - 抱歉,已更正链接 【参考方案1】:

作者过于简单化了。他是说animal 下的所有内容都可以看作是在同一个模块中,尽管事实上animal.dog 中的名称将在它们自己的命名空间中。

【讨论】:

【参考方案2】:

也许重点只是一个包只是一种特定类型的模块。

/base
    /animals
        /__init__.py
        /dog.py

这只是意味着您在__init__.py 中定义或导入的任何内容都将在animals 模块中可见。

所以animals 是一个模块(即包),animals.dog 是一个模块,它是animals 的子模块,但不是包。

这也意味着如果你有一个简单的模块animals,你可以在下一个版本中用同名的包来取代它,并安排好让你的用户不会注意到差异。

如果您希望包子模块中的所有类构成一个用户可见的模块(命名空间),您必须在__init__.py 中为每个子模块定义这样的一行:

from animals.dog import *

【讨论】:

请查看我添加到我的问题的编辑 - 我认为它清楚地表明这个答案错过了作者的观点(除非我在你的答案中也遗漏了一些东西:)) 您链接到的文本肯定是错误的并且容易被误解。但我的回答只是我认为对一个密切相关的问题的合理回答,它还展示了如何使它成为现实——如何使它看起来像所有函数和类都在同一个 .py 文件中定义.链接的文本暗示这是自动的,但不是,它只是一种可能性。 但是在更高的层次上,所写的正确的,因为一个包在单个***模块名后面收集了尽可能多的 .py 文件的内容。但是,它不会立即收集模块命名空间中的所有属性。【参考方案3】:

不是一个真正的答案,但我还不能发表评论(叹气!):

因为对于 Python 程序员来说,diveintopython 是大量使用/引用/参考的资源(至少在他们开始时),您应该就这个缺陷真正联系作者,因为它也会误导其他人。在diveintopython3的主页上有一些联系方式,也可以在github上作为issue提交。

【讨论】:

【参考方案4】:

我不能很好地解释它,但也许下面的代码会有所帮助。如果我保持您的第一个文件结构不变,而是修改第二个文件结构,使其在 animals.py 文件中包含以下内容:

class Dog:
    def bark(self): pass
dog=Dog()

那么在这两种情况下,

from base import animals
animals.dog.bark()

会起作用的。

【讨论】:

嗯,是的,在那种特定情况下,两者都可以工作。但作者的主张远不止于此——模块表现为一个大模块。您已经证明,包中的模块的行为有点像一个具有属性的大模块,我相信大多数人都知道这一点:) 引用作者的话:“好像所有 函数classes 在单个 .py 中”——这明确意味着 animal.bark 就足够了。

以上是关于python 包(多文件模块)的行为与一个大模块完全一样吗?的主要内容,如果未能解决你的问题,请参考以下文章

python 虚拟环境与包安装

使用 `with:` 语句的 Python 文件锁模块行为

Python常用模块——包&跨模块代码调用

python进阶-- 02 如何使用模块

python0.13-----模块/包概述

python模块与模块之间的调用包与包之间的调用