Python 子模块导入使用 __init__.py

新手上路,请多包涵

我正在学习 Python,但我无法弄清楚 __init__.py 中的导入是如何工作的。

我从 Python 教程 中了解到 __init__.py 文件初始化了一个包,我可以在这里导入子包。

不过,我做错了什么。你能为我(以及未来的 Python 学习者)解释我做错了什么吗?

这是我正在尝试做的一个简化示例。

这是我的文件结构:

 package
    __init__.py
    test.py
    subpackage
        __init__.py
        hello_world.py

hello_world.py 的内容:

 def do_something():
    print "Hello, world!"

subpackage/__init__.py 是空的。

package/__init__.py 包含:

 import test.submodule.do_something

最后, test.py 包含:

 do_something()

这就是我尝试使用 OSX 终端和 Python 3 运行 hello_world.py 的方式:

 python test.py

然后 Python 抛出以下错误:

 NameError: name 'do_something' is not defined

原文由 Benjamin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 454
2 个回答

您可能已经了解,当您导入 模块 时,解释器会创建一个新的命名空间,并使用新命名空间作为本地和全局命名空间来执行该模块的代码。当代码完成执行时,模块名称(或任何 as 子句中给出的名称)绑定到刚刚在导入命名空间中创建的模块对象,并根据其 __name__sys.modules

When a qualified name such as package.subpackage.module is imported the first name ( package ) is imported into the local namespace, then subpackage is imported into package 的命名空间,最后 module 导入到 package.subpackage 的命名空间。使用 from ... import ... as ... 的导入执行相同的操作序列,但导入的对象直接绑定到导入模块命名空间中的名称。包名称未绑定到您的本地命名空间这一事实并不意味着它尚未被导入(检查 sys.modules 将显示)。

包中的 __init__.py 与模块的 .py 文件具有相同的功能。具有结构的 被编写为一个目录,该目录还可以包含任何子包的模块(常规 .py 文件)和子目录(也包含 __init__.py 文件)。导入包时,会创建一个新的命名空间,并使用该命名空间作为本地和全局命名空间来执行包的 __init__.py 。因此,为了回答您的问题,我们可以通过省略顶级包来剥离您的文件存储,当 test.py 作为程序运行时,解释器将永远不会考虑它。它看起来像这样:

 test.py
subpackage/
    __init__.py
    hello_world.py

现在, subpackage 不再是子包,因为我们已经删除了不相关的包含包。关注 do_something 名称未定义的原因可能会有所帮助。 test.py 不包含任何导入,因此不清楚您如何期望 do_something 获得意义。你可以通过使用一个空的 subpackage/__init__.py 让它工作,然后你会写 test.py 作为

from subpackage.hello_world import do_something
do_something()

或者,您可以使用 subpackage/__init__.py 读取

from hello_world import do_something

导入包时,它会在 subpackage 命名空间中建立 do_something 函数。然后使用 test.py 从包中导入函数,如下所示:

 from subpackage import do_something
do_something()

具有相同 __init__.py 的最终替代方案是使用 test.py 只需导入(子)包,然后使用相对命名来访问所需的函数:

 import subpackage
subpackage.do_something()

在您的本地名称空间中访问它。

对于空的 __init__.py 这也可以通过 test.py 阅读来实现

import subpackage.hello_world
subpackage.hello_world.do_something()

甚至

from subpackage.hello_world import do_something
do_something()

一个空的 __init__.py 意味着顶级包命名空间将只包含程序导入的任何子包的名称,这允许你只导入你需要的子包。这使您可以控制顶级包的名称空间。

虽然完全有可能在 __init__.py 中定义类和函数,但更正常的方法是将内容从子模块导入该命名空间,以便导入者只需导入顶级包即可访问其内容单级属性引用,甚至使用 from 只导入您特别想要的名称。

最终,让您保持直觉的最佳工具是清楚地了解 import 的工作原理以及它的各种形式对导入命名空间的影响。

原文由 holdenweb 发布,翻译遵循 CC BY-SA 4.0 许可协议

首先,您必须了解 import 是如何工作的:

 import test.submodule.do_something

将尝试从 --- 加载 do_something submodule 本身从 test --- 加载。

你想从 subpackage 加载一些东西,所以从那个开始:

 import subpackage

很好,加载 subpackage/__init__.py

现在,您需要文件(“模块”)中的 do_something() 函数 hello_world.py 。简单的:

 from subpackage.hello_world import do_something

你完成了!大声朗读这行,它完全按照它说的做:导入 do_something 来自模块 hello_world 它在 subpackage 包中

尝试在 test.py

 from subpackage.hello_world import do_something

do_something()

它应该工作得很好。

现在,第二个问题:

__init__.py 不会在 package/ 中调用,因为你不使用 package/ 作为一个包。 __init__.py 将在您导入 package/ 或其中的任何内容时使用,例如:

 from package import test

否则,它根本不会被加载。

However, if you want to load do_something() on the import of subpackage, put from submodule.hello_word import do_something in subpackage/__init__.py , and then, in you test.py ,做一个 import subpackage

原文由 evuez 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏