ModuleNotFoundError:没有名为“ __main __。xxxx”的模块;'__main__'不是软件包


71

当前尝试在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给出错误。这里需要更改什么?


1
前导“。” 仅当文件所在的文件位于软件包中时,它才能按照您想要的方式工作。
anonymoose

2
@anonymoose是“ proj”不是软件包吗?由于它具有 init .py3?
mpseligson

3
您不能使用开头的“。” 导入文件中,并且可以直接使用Python运行文件时以所需的方式运行。您必须导入文件。如果放在其他文件之外proj是有import moduleA它,我相信你会看到你期待的输出。
anonymoose

Answers:


49

.moduleB是相对导入。相对仅在先导入或加载父模块时才起作用。这意味着您需要proj在当前运行时环境中的某个位置导入。当您使用command时python3 moduleA.py3,将没有机会导入父模块。您可以:

  • from proj.moduleB import moduleB 要么
  • 您可以创建另一个脚本(假设run.py)来调用from proj import moduleA

祝您踏入Python的那片好运。


26

除了md-sabuj-sarker的答案外,Python模块文档中还有一个非常好的示例。

这就是文档所说的intra-package-references

请注意,相对导入基于当前模块的名称。由于主模块的名称始终为"__main__",因此打算用作Python应用程序主模块的模块必须始终使用绝对导入。

如果您运行python3 moduleA.py3moduleA它将用作主模块,因此使用绝对导入看起来很正确。

但是,请注意,此绝对导入(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

或者,您可以按照此处此处的建议删除.in from .moduleB import,它似乎可行,尽管我的PyCharm(2018.2.4)将此标记为“未解决的参考”,但无法自动完成。


3
为我工作。pycharm红色点亮了导入行,但运行没有问题!(对不起,pycharm)
王凯

2
@KaiWang为避免PyCharm将其标记为“未解决的引用”,可以将根目录标记为源root
本雅明·贾法里

25

前言

我正在开发一个项目,该项目实际上是可以通过pip安装的Python程序包,但是它还提供了命令行界面。使用安装了项目后pip install .,我的项目运行没有问题,但是,在更改了一个项目文件中的某些内容后,每次由谁来执行此操作?我需要通过简单的操作来完成整个工作python mypackage/main.py

/my-project
    - README.md
    - setup.py
    /mypackage
      - __init__.py
      - main.py
      - common.py

相同问题的不同面孔

我尝试main.pycommon.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文档中对此进行了解释:

请注意,相对导入基于当前模块的名称。由于主模块的名称始终为__main__,因此打算用作Python应用程序主模块的模块必须始终使用绝对导入。

当我安装软件包pip install .并运行它时,它运行良好。我还能够mypackage.main在Python控制台中导入模块。因此,看起来只有直接运行它才有问题。

绝对进口

让我们遵循文档中的建议,并将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'

解释器很正确,您没有安装这样的软件包,这可能会很令人讨厌。

解决方案

对于简单的Python应用程序

只需使用绝对导入(不带点),一切都会好起来的。

对于开发中的可安装Python应用程序

请使用相对导入,或使用开头带有包名的导入,因为在安装应用程序时,您需要这样的导入。在开发中运行此类模块时,可以使用以下-m选项执行Python :

-m mod : run library module as a script (terminates option list)

因此python mypackage/main.py,请改为这样做:python -m mypackage.main


2
你是一个超级英雄。感谢您对为什么会这样的清晰解释。
nilleb

我们可以查看样板文件中的内容吗?
joe hoeller

1

也许您可以在导入模块之前执行此操作:

moduleA.py3

import os
import re
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from moduleB import ModuleB
ModuleB.hello()

将当前目录添加到环境目录


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.