【问题标题】:Python imports - ModuleNotFoundError: No module named XPython 导入 - ModuleNotFoundError:没有名为 X 的模块
【发布时间】:2020-03-11 02:15:06
【问题描述】:

我可能已经阅读了这里关于进口的所有帖子,但我仍然无法弄清楚进口发生了什么,我花了几个小时试图让一个非常简单的例子工作并且真的把我的头发拉出来了。

我正在使用 python 3.7 和 pycharm,但我正在从命令行运行我的代码,我正在使用 pytest 进行单元测试。

我的项目结构是:

my_message_validator/
    __init__.py

    module_1/
        __init.py__
        foo.py

    module_2/
        __init.py__
        bar.py
        baz.py

    module_3
        context.py
        test_all.py

module_1.init.py

from module_1 import foo

module_2.init.py

# For some reason pycharm doesnt complain when I use '.' but if I use module_2 it does
from . import bar, baz

如果我尝试从命令行运行我的代码或我的测试,无论我如何移动,我似乎都会得到ModuleNotFoundError: No module named,当我设法让测试工作时,我仍然无法自行运行我的代码从命令行。

如何将module_1 导入module_2,这些实际上是包吗?我来自 java,发现导入更容易理解,我发现 python 导入非常混乱......

然后我怎样才能将我需要的任何东西导入我的测试模块\包\文件夹context.py

目前测试上下文如下:

import os
import sys

# Is this needed as it doesnt seem to do anything?
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from module_1.foo import Foo

from module_2 import bar, baz

test_all.py 我试图从上下文文件中导入,如下所示:

from .context import bar,baz
from .context import Foo

# Calling in test like
Foo.load_file(file)

bar.method_one()
baz.method_two()

我需要所有__init.py__ 文件吗?我应该在其中放入什么来使我的方法和类公开\公开?我希望整个包是可重用的,因此希望能够将其视为 java 中的 jar 文件。

任何帮助都将不胜感激,因为似乎每次我更改某些内容时都会在不同的地方出错,python 现在似乎比 java 复杂得多。

【问题讨论】:

  • 您是否尝试过像这样导入: from my_message_validator.module_1.foo import Foo ?

标签: python python-3.x module package python-3.7


【解决方案1】:

首先,不要使用相对导入(使用.),因为众所周知它会导致multiple issues。始终写相对于项目根目录的导入。例如,您为from module_1.foo import Foo 做得很好。您还应该在test_all.pycontext.py 中执行此操作。此外,在使用相对导入后,__init__.py 文件在您的情况下可以留空。

很可能,Python 解释器找不到您的模块,因为PYTHONPATH 环境变量不包含您项目的根目录。如果您在脚本之前运行export PYTHONPATH="YOUR_PROJECT_ROOT_ABSOLUTE_PATH:$PYTHONPATH",它应该会按预期运行。为确保始终设置此变量,您可以将导出语句添加到您的 shell 配置文件中(例如 .bashrc.bash_profile)。

和作者聊了聊,原来还有第四期。这是一个名称冲突,就像 other question 中的那样。在他的项目目录中,module_1 实际上被称为foo,就像它的孩子foo.py,这让解释器感到困惑。

【讨论】:

  • 那么你会建议我摆脱所有的__init__.py files吗?如果 bar 和 baz 只包含函数而不包含类,那么导入它们的正确方法是什么?
  • 是的,我建议您删除所有__init__.py 文件。关于barbaz,您可以从它们中导入函数,就像在Java 中导入类一样。也就是说,您可以使用from module_2.bar import my_bar_functionfrom module_2.baz import my_baz_function。然后,您只需在脚本中调用my_bar_function()my_baz_function()
  • 在测试中使用context.py 有什么意义吗?我遵循了关于如何创建包的教程,它似乎正在处理测试套件的导入,然后从 .context 导入
  • 这通常取决于不同测试之间共享多少代码。我建议你在没有context.py 的情况下启动项目,然后再添加它,以防你发现自己在不同的测试中一直在导入相同的东西。
  • @djvg 感谢您的评论。我同意,并补充说一些 linter 或静态分析工具不会探索不是常规包的目录。我编辑了答案。
【解决方案2】:

您是否尝试过像这样导入:

from my_message_validator.module_1.foo import Foo
from my_message_validator.module_2 import bar, baz

【讨论】:

  • 我曾认为使用__init__.py 文件然后在那里导出(使用导入)意味着我不必提供所有内容的完整路径。用python开发的规范是什么?
  • 如果我要使用绝对路径而不是相对路径,我还需要处理__init__.py 文件吗?
  • 当我将绝对路径添加到我的单元测试时,我得到了这个错误而不是ModuleNotFoundError: No module named 'my_message_validator',尽管 pycharm 似乎对这种格式很满意
  • 导入的绝对路径是必需的,因为 Python 正在通过根目录识别您的项目路径。其余的模块你需要提到 root 以后。
  • Rest of the modules you'll require to mention root onwards,你能用一个例子更新你的答案吗,我不知道你的意思。
【解决方案3】:

我有同样的情况。
我以这种方式启动应用程序:

flask run

每次我在网站上收到ModuleNotFoundError 错误。
当我像这样启动应用程序时:

python3 -m flask run

应用程序启动时没有错误:-)。

【讨论】:

    猜你喜欢
    • 2021-05-16
    • 1970-01-01
    • 2017-09-29
    • 1970-01-01
    • 1970-01-01
    • 2019-12-02
    • 1970-01-01
    • 2019-04-12
    • 2020-10-03
    相关资源
    最近更新 更多