目前正在尝试使用Python3并使用绝对导入将一个模块导入另一个模块但我收到错误ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package
。考虑一下这个项目结构:
proj
__init__.py3 (empty)
moduleA.py3
moduleB.py3
moduleA.py3
from .moduleB import ModuleB
ModuleB.hello()
moduleB.py3
class ModuleB:
def hello():
print("hello world")
然后运行python3 moduleA.py3
会出错。需要在这里改变什么?
答案 0 :(得分:27)
.moduleB
是相对导入的。相对仅在首先导入或加载父模块时有效。这意味着您需要在当前运行时环境中的某处导入proj
。当您使用命令python3 moduleA.py3
时,它没有机会导入父模块。你可以:
from proj.moduleB import moduleB
或run.py
,以调用from proj import moduleA
祝你旅途愉快地前往Python的绝佳之地。
答案 1 :(得分:10)
除了md-sabuj-sarker的答案,Python modules documentation中还有一个很好的例子。
这就是文档对intra-package-references的评价:
请注意,相对导入基于当前模块的名称。由于主模块的名称始终为
"__main__"
,因此打算用作Python应用程序主模块的模块必须始终使用绝对导入。
如果您运行python3 moduleA.py3
,则moduleA
被用作主要模块,因此使用绝对导入看起来是正确的选择。
但是,请注意,如果出于某种原因该软件包包含与该软件包同名的模块文件,则此绝对导入(from package.module import something
)会失败(至少在我的Python 3.7中)。因此,例如,如果您拥有(使用OP的示例),它将失败:
proj/
__init__.py (empty)
proj.py (same name as package)
moduleA.py
moduleB.py
在这种情况下,您会得到:
ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package
或者,您可以按照建议的here和here删除.
中的from .moduleB import
,尽管我的PyCharm(2018.2.4)对此做了标记作为“未解决的参考”,并且无法自动完成。
答案 2 :(得分:4)
我正在开发一个项目,该项目实际上是可以通过 pip 安装的Python程序包,但它也提供了命令行界面。使用pip install .
安装项目后,我的项目运行没有问题,但是,在更改了其中一个项目文件中的内容后,每次由谁来执行此操作?我需要通过简单的python mypackage/main.py
运行整个过程。
/my-project
- README.md
- setup.py
/mypackage
- __init__.py
- main.py
- common.py
我尝试从main.py
模块中导入common.py
中的一些函数。我尝试了会导致不同错误的不同配置,并希望与您分享我的观察结果,并为将来我留下简短的笔记。
我首先尝试的是相对导入:
from .common import my_func
我使用以下简单的命令运行应用程序:python mypackage/main.py
。不幸的是,这产生了以下错误:
ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
此问题的原因是main.py
由python
命令直接执行,因此成为名为__main__
的主模块。如果将这些信息与我们使用的相对导入相关联,则会得到错误消息__main__.common
中的内容。 Python documentation中对此进行了解释:
请注意,相对导入基于当前模块的名称。由于主模块的名称始终为
__main__
,因此打算用作Python应用程序主模块的模块必须始终使用绝对导入。
当我使用pip install .
安装软件包并运行它时,它运行良好。我还能够在Python控制台中导入mypackage.main
模块。因此,似乎只有直接运行它才有问题。
让我们遵循文档中的建议,并将import声明更改为其他内容:
from common import my_func
如果我们现在现在尝试像以前一样运行此命令:python mypackage/main.py
,那么它将按预期运行!但是,当您像我一样在使用 pip 安装后开发出需要作为独立命令行工具工作的东西时,有一点需要注意。我使用pip install .
安装了程序包,然后尝试运行它...
ModuleNotFoundError: No module named 'common'
更糟糕的是,当我打开Python控制台并尝试手动导入main
模块(import mypackage.main
)时,出现了与上述相同的错误。原因很简单:common
不再是相对导入,因此Python尝试在已安装的软件包中找到它。我们没有这样的软件包,这就是为什么它失败了。
只有在创建使用python
命令执行的典型Python应用程序时,采用绝对导入的解决方案才能很好地工作。
还有第三种可能性可以导入common
模块:
from mypackage.common import my_func
这与相对导入方法没有太大区别,只要我们从mypackage
的上下文中进行操作即可。同样,尝试使用python mypackage/main.py
运行此命令的结果类似:
ModuleNotFoundError: No module named 'mypackage'
解释器是正确的,您没有安装这样的软件包。
只需使用绝对导入(不带点),一切都会好起来的。
使用相对导入,或使用开头带有软件包名称的导入,因为在安装应用程序时需要这样的导入。在开发中运行此类模块时,可以使用-m
选项执行Python:
-m mod : run library module as a script (terminates option list)
因此,不要像python mypackage/main.py
那样做:python -m mypackage.main
。
答案 3 :(得分:0)
也许您可以在导入模块之前执行此操作:
moduleA.py3
import os
import re
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from moduleB import ModuleB
ModuleB.hello()
将当前目录添加到环境目录
答案 4 :(得分:0)
只需将运行应用程序的文件重命名为 main.py :
from app import app
if __name__ == '__main__':
app.run()