ModuleNotFoundError:没有名为'__main __.xxxx'的模块; '__main__'不是包

mps*_*son 46 import module python-3.x

目前正在尝试使用Python3并使用绝对导入将一个模块导入另一个模块但我收到错误ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package.考虑这个项目结构:

proj
    __init__.py3 (empty)
    moduleA.py3
    moduleB.py3
Run Code Online (Sandbox Code Playgroud)

moduleA.py3

from .moduleB import ModuleB
ModuleB.hello()
Run Code Online (Sandbox Code Playgroud)

moduleB.py3

class ModuleB:
    def hello():
        print("hello world")
Run Code Online (Sandbox Code Playgroud)

然后运行python3 moduleA.py3给出错误.这里有什么需要改变的?

谢谢!

小智 39

.moduleB是相对重要的.相对仅在首先导入或加载父模块时有效.这意味着您需要proj在当前运行时环境中的某处导入.当您使用命令时python3 moduleA.py3,它没有机会导入父模块.您可以:

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

祝你旅途愉快,前往Python这片令人敬畏的土地.

  • 而且它是可笑的进口产品。 (2认同)

ita*_*chi 31

前言

我正在开发一个项目,它实际上是一个可以通过pip安装的 Python 包,但它也公开了一个命令行界面。使用 安装后运行我的项目没有问题pip install .,但是,嘿,在更改项目文件之一中的某些内容后,谁每次都这样做?我需要通过 simple 运行整个过程python mypackage/main.py。

/my-project
    - README.md
    - setup.py
    /mypackage
      - __init__.py
      - main.py
      - common.py
Run Code Online (Sandbox Code Playgroud)

同一个问题的不同面

我尝试main.py从我的common.py模块中导入一些函数。我尝试了不同的配置,但出现了不同的错误,我想与您分享我的观察结果,并为未来的我留下一个简短的笔记。

相对导入

我尝试的第一个是相对导入:

from .common import my_func
Run Code Online (Sandbox Code Playgroud)

我用 simple: 运行了我的应用程序python mypackage/main.py。不幸的是,这给出了以下错误:

ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
Run Code Online (Sandbox Code Playgroud)

出现这个问题的原因是main.py直接被pythoncommand执行了,从而变成了主模块命名为__main__。如果我们连与我们使用的相对进口这些信息,我们得到了什么,我们有错误消息:__main__.common。这在Python 文档中进行了解释:

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

当我安装我的包pip install .然后运行它时,它运行得非常好。我还能够mypackage.main在 Python 控制台中导入模块。所以看起来只有直接运行它才有问题。

绝对进口

让我们按照文档中的建议将导入语句更改为不同的内容:

from common import my_func
Run Code Online (Sandbox Code Playgroud)

如果我们现在尝试像以前一样运行它:python mypackage/main.py,那么它会按预期工作!但是,当您像我一样开发一些在使用pip安装后需要作为独立命令行工具工作的东西时,有一个警告。我安装了我的包,pip install .然后尝试运行它......

ModuleNotFoundError: No module named 'common'
Run Code Online (Sandbox Code Playgroud)

更糟糕的是,当我打开 Python 控制台并尝试main手动导入模块 ( import mypackage.main) 时,出现与上述相同的错误。原因很简单:common不再是相对导入,因此 Python 尝试在已安装的包中找到它。我们没有这样的包,这就是它失败的原因。

只有当您创建一个使用python命令执行的典型 Python 应用程序时,绝对导入的解决方案才能很好地工作。

使用包名导入

还有第三种可能导入common模块:

from mypackage.common import my_func
Run Code Online (Sandbox Code Playgroud)

这与相对导入方法没有太大区别,只要我们从mypackage. 再次,尝试以python mypackage/main.py类似的方式运行它:

ModuleNotFoundError: No module named 'mypackage'
Run Code Online (Sandbox Code Playgroud)

这有多烦人,解释器是对的,你没有安装这样的包。

解决方案

对于简单的 Python 应用程序

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

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

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

-m mod : run library module as a script (terminates option list)
Run Code Online (Sandbox Code Playgroud)

因此,而不是python mypackage/main.py,像这样做:python -m mypackage.main。

  • 你是一个超级英雄。感谢您对“为什么”发生这种情况的清晰解释。 (3认同)

djv*_*jvg 20

除了md-sabuj-sarker的答案之外,Python模块文档中还有一个很好的例子.

这就是文档对包内引用的说法:

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

如果运行python3 moduleA.py3,moduleA则用作主模块,因此使用绝对导入看起来是正确的事情.

但是,请注意,from package.module import something如果由于某种原因,程序包包含与程序包同名的模块文件(至少在我的Python 3.7上),则此绝对import()将失败.所以,例如,如果你有(使用OP的例子)它会失败:

proj/
    __init__.py (empty)
    proj.py (same name as package)
    moduleA.py
    moduleB.py
Run Code Online (Sandbox Code Playgroud)

在这种情况下你会得到:

ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package

或者,您可以删除.in from .moduleB import,如此处和此处所示,这似乎有效,尽管我的PyCharm(2018.2.4)将此标记为"未解析的引用"并且无法自动完成.

  • 为我工作。pycharm红色点亮了导入行,但运行没有问题!(对不起,pycharm) (2认同)
  • @KaiWang为了避免PyCharm将其标记为“未解析的引用”,您可以[将根目录标记为源根目录](https://www.jetbrains.com/help/pycharm/configuring-folders-within-a-content-根.html)。 (2认同)