为什么不能导入子模块?

时间:2020-02-20 00:59:27

标签: python python-import

我的项目结构如下:

/project
    main.py
    /a_module
        __init__.py
        /sub_module
            __init__.py
            some_file.py

main.py

from a_module import main_api

a_module / __ init __。py

from sub_module import sub_api

sub_module / __ init __。py

from some_file import detail_api

a_module / __ init __。py 中,出现Unable to import 'sub_module'错误。

为什么我不能导入'sub_module'

当我更改为相对路径时,解决错误。

from .sub_module import sub_api

但是我不明白,__init__.py是否为公共设计了模块的API?为什么不将sub_module视为模块而不是目录?对我来说这真是个糟糕的设计...

1 个答案:

答案 0 :(得分:0)

__init__.py在导入包含它的软件包时执行。但这不是你的问题。您的问题是,除非明确地是相对的,否则模块导入始终是绝对的。这意味着它们必须从sys.path中的 some 目录链接。默认情况下,这包括工作目录,因此,当您从main.py内部运行project时,它可以找到a_module,而找不到其他内容。

from sub_module import sub_api
a_module/__init__.py中的

无效,因为导入始终是绝对的,除非明确地是相对的。因此导入显示为“从某个sys.path根目录开始,找到一个名为sub_module的顶级程序包,然后从其中导入sub_api”。由于不存在这样的模块,因此会出现错误。 from .sub_module import sub_api之所以有效,是因为您选择了相对导入,因此它不会从sys.path开始。

有关为什么要执行此操作的示例,我将在默认法律绝对导入为法律({{1}启用Py3行为,这就是我们修复它的方法,但是尽管文档说了什么,但Py2从未默认启用它,唯一的默认行为是相对导入)。我们的布局是:

from __future__ import absolute_import

现在,我们天真地想起了嘿,我们将所有程序包放在一个共享的顶级命名空间下,并且子程序包涵盖其中的广泛类别,并且由于我们有许多其他的用于基础数学的实用程序,因此将它们放在 teamnamespace/ module.py math/ mathrelatedsubmodule.py othermathsubmodule.py 。问题是,对于像teamnamespace.math这样的 non 数学模块,它们的工作时间是:

teamnamespace.module

它默认为相对查找,并将import math # or from math import ceil 导入为teamnamespace.math(完全无用的导入,因为它只是一个名称空间包,所有功能都在子模块中),而不是内置的-在math模块中。实际上,如果没有Python 3行为,就没有合理的方法从math下的模块中获取内置math模块。鉴于Python 3的行为,您可以选择其中之一或两者(通过使用teamnamespace来别名一个或另一个,而不会产生歧义:

as