相对导入 - 模块未找到错误:没有名为x的模块

417

这是我第一次认真尝试Python 3,但似乎失败了。我有以下两个文件:

  1. test.py
  2. config.py

config.py中定义了几个函数和几个变量。我已将其简化为以下内容:

config.py

debug = True

test.py

import config
print (config.debug)

我也有一个__init__.py

但是,我遇到了以下错误:

ModuleNotFoundError: No module named 'config'

我知道在py3中习惯使用绝对导入:

from . import config

然而,这会导致以下错误:

ImportError: cannot import name 'config'

所以我现在不知道该怎么办... 非常感谢任何帮助。:)


2
我无法重现这个错误,你是如何执行这段代码的? - Copperfield
3
我使用Python自带的IDLE来执行它,也可以通过python test.py命令来执行,都能正常运行。虽然我没有PyCharm,但可能是PyCharm的某些配置问题导致了这个问题。 - Copperfield
2
非常奇怪。我正在使用WinPython - 只需从python.org下载vanilla Python 3.6,它就可以正常工作。从未想过检查解释器!谢谢! - blitzmann
2
我的猜测是PYTHONPATH出了点问题。请检查您的IDE设置和/或系统环境变量。 - Martin Tournoij
4
我有完全相同的问题。这不是PyCharm的问题!这是Python3的问题。在Python2中可以工作,但是在使用Python3时,你会看到这个错误!非常令人沮丧。 - user3159377
显示剩余5条评论
19个回答

6

尝试

from . import config

这样做的作用是从相同的文件夹级别导入。如果你直接尝试导入,它会认为它是下属。


4
这个例子适用于Python 3.6。
我建议在PyCharm中前往“运行->编辑配置”,删除所有条目,然后再尝试通过PyCharm运行代码。
如果这不起作用,请检查您的项目解释器(设置->项目解释器)和运行配置默认值(运行->编辑配置...)。

3

您可以使用这些语句设置工作目录,我用python3成功地实践过。

import os
import sys
sys.path.insert(1, os.getcwd())

3

如原帖评论所述,这似乎是由于我使用的Python解释器出了问题,而不是Python脚本出了问题。我从WinPython包切换到来自python.org的官方Python 3.6版本,问题得以解决。感谢大家的帮助 :)


2
哎呀,不太情愿说这个,但我也遇到了同样的问题。重新创建环境可以解决这个问题。在我的情况下,当运行测试时,我会收到这个错误。在相同的环境中,尝试导入相同的模块是可以工作的。重新创建环境解决了所有问题(使用相同的Python版本3.6)。 - naoko
2
不同的IDE处理路径(特别是项目源文件(视图、模块、模板等))的方式不同。如果您的项目结构和编码正确,则应该适用于所有(标准)IDE。如果在流行的IDE(如WinPython)中遇到问题,则问题确实来自您的项目。如上所述,“您必须向模块添加一个点”,这是由用户3159377提出的,应该是被接受的答案。 - winux

1

对我来说,只需简单地添加当前目录即可。

使用以下结构:

└── myproject
    ├── a.py
    └── b.py

a.py:

from b import some_object
# returns ModuleNotFound error

from myproject.b import some_object
# works

0

让Bash自动识别您所在的项目目录:

sudo nano ~/.bashrc

或者

sudo nano ~/.bash_profile

在 bash 文件底部:
function set_pythonpath {
    export PYTHONPATH="$(pwd):$PYTHONPATH"
}

PROMPT_COMMAND=set_pythonpath

保存并退出:

  • Ctrl + X
  • Y

通过以下方式测试您的更改:

cat ~/.bashrc

0
根据我的经验,PYTHONPATH 环境变量并不总是有效。
在我的情况下,只有当我添加了绝对路径 "/Users/bob/project/repo/lambda" 时,我的 pytest 才能正常工作: sys.path.insert(0, "/Users/bob/project/repo/lambda")

不要忘记 import sys :) - llincolnatal
2
目前你的回答不够清晰。请编辑并添加更多细节,以帮助其他人理解它如何回答所提出的问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community

0

我看到很多答案导入了sysos。这是一个GitHub Copilot给我的更短的方法,但还没有提到:

import sys

sys.path.append(__file__.rsplit("/", 1)[0])

将这行代码添加到我的Python脚本顶部也解决了问题。

0
现有的答案很好地解释了这个问题可能的原因。对于那些由尝试相对导入引起的异常情况,我发现以下方法可以帮助解决:
  1. 在项目文件中搜索 from .
  2. 将所有这些导入更新为绝对导入
  3. 对于所有新的导入,使用绝对导入
这样做可能会有些麻烦,而且不够灵活,但可以避免循环导入引起的错误。
根据我的经验,另一个常见但较少见的问题是命名空间冲突。这种错误往往是最难以调试的,因为错误消息中很少有冲突的指示。
几乎所有情况下,都需要进行手动的上下文特定调试。然而,以下是一个一般性的示例:
.
└── root/
    ├── apps/
    │   ├── ...
    |   |── app2/
    │   └── app2/
    │       ├── ...
    │       └── main.py
    └── venv/
        ├── ...
        └── Lib/
            └── site-packages/
                ├── ...
                └── django/
                    ├── ...
                    └── apps

root/apps/app1/main.py文件中,想象一下你从apps.app2导入了某些东西,并且还尝试从django.apps导入。这通常会导致问题,因为apps从两个位置进入命名空间。
然而,错误消息通常会让人误以为是循环导入a导入bb导入a,实际上是对ab的真正含义产生了混淆。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接