相对导入 - ModuleNotFoundError:没有名为 x 的模块

Posted

技术标签:

【中文标题】相对导入 - ModuleNotFoundError:没有名为 x 的模块【英文标题】:Relative imports - ModuleNotFoundError: No module named x 【发布时间】:2017-09-29 10:03:26 【问题描述】:

这是我第一次真正坐下来尝试 python 3,但似乎失败得很惨。我有以下两个文件:

    test.py 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'

所以我不知道在这里做什么......非常感谢任何帮助。 :)

【问题讨论】:

我无法重现错误,你如何执行这段代码? 我用python自带的idle和python test.py执行它,它工作得很好。我没有 pyCharm,但可能是 pyCharm 的一些错误配置导致了问题 很奇怪。我正在使用 WinPython - 只需从 python.org 下载 vanilla Python 3.6,它就可以正常工作。从没想过要检查口译员!谢谢! 我的猜测是 PYTHONPATH 正在发生一些奇怪的事情。检查您的 IDE 设置和/或系统环境变量。 我也有同样的问题。这不是pycharm!它是python3。它在python2中工作,但是在使用python3时,你会看到这个错误!非常令人沮丧。 【参考方案1】:

我在一台 Linux 机器上工作。我在运行 python my_module/__main__.py 时遇到了同样的问题。

如果您在运行脚本之前运行命令 export PYTHONPATH=.,则该错误已修复。

export PYTHONPATH=.
python my_module/__main__.py

【讨论】:

【参考方案2】:

您必须将项目路径附加到PYTHONPATH 并确保使用绝对导入


适用于 UNIX(Linux、OSX、...)

export PYTHONPATH="$PYTHONPATH:/path/to/your/project/"

适用于 Windows

set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\project\

绝对导入

假设我们有如下的项目结构,

└── myproject
    ├── mypackage
    │   ├── a.py
    └── anotherpackage
        ├── b.py
        ├── c.py
        └── mysubpackage
            └── d.py

只需确保从项目的根目录开始引用每个导入。例如,

# in module a.py
import anotherpackage.mysubpackage.d

# in module b
import anotherpackage.c
import mypackage.a

更全面的解释请参考文章How to fix ModuleNotFoundError and ImportError

【讨论】:

非常感谢@Giorgos!当您尝试在 docker 映像中设置根目录时尤其如此。【参考方案3】:

pip install config

显然我不能只输入 18 个字符,因此这个文本!

【讨论】:

【参考方案4】:

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

使用以下结构:

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

a.py:

from b import some_object
# returns ModuleNotFound error

from myproject.b import some_object
# works

【讨论】:

【参考方案5】:

TL;DR:您不能从您执行的文件中进行相对导入,因为__main__ 模块不是包的一部分。

绝对导入 - 导入 sys.path 上可用的东西

相对导入 - 导入相对于当前模块的东西,必须是包的一部分

如果您以完全相同的方式运行这两种变体,则其中一种应该可以工作。这是一个示例,可以帮助您了解正在发生的事情。让我们添加另一个 main.py 文件,其整体目录结构如下:

.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py

让我们更新test.py 看看发生了什么:

# config.py
debug = True
# test.py
print(__name__)

try:
    # Trying to find module in the parent package
    from . import config
    print(config.debug)
    del config
except ImportError:
    print('Relative import failed')

try:
    # Trying to find module on sys.path
    import config
    print(config.debug)
except ModuleNotFoundError:
    print('Absolute import failed')
# main.py
import ryan.test

让我们先运行test.py

$ python ryan/test.py
__main__
Relative import failed
True

这里的“测试” __main__ 模块并且不知道属于包的任何事情。但是import config 应该可以工作,因为ryan 文件夹将被添加到sys.path

让我们改为运行main.py

$ python main.py
ryan.test
True
Absolute import failed

这里的 test 在 "ryan" 包内,可以执行相对导入。 import config 失败,因为 Python 3 中不允许隐式相对导入。

希望这会有所帮助。

P.S.:如果您坚持使用 Python 3,则不再需要 __init__.py 文件。

【讨论】:

我可以做些什么来使绝对导入始终有效吗?比如,在/some/path/my_module/__init__.py 内调用sys.path.append('/some/path/my_module') @JamesT。是的,在运行时修改sys.path 是很常见的(github.com/…)。您还可以设置 PYTHONPATH 环境变量。 "如果您坚持使用 Python 3,则不再需要 __init__.py 文件。"有趣的。你能详细说明一下吗?我的印象是包解析机制在 2 和 3 之间没有太大变化。 “如果你坚持使用 Python 3,则不再需要 __init__.py 文件。” 相反,如果我们想要一个包在其中工作,你能描述一下吗2和3?并查看可悲的过时 2009 What is __init__.py for? 及其最受好评的回答 “它是一个包的一部分”。我们需要开始强调 "regular package [old, pre-3.3]""namespace package [3.3+]" 的区别。 很抱歉在评论部分发送垃圾邮件,但是......伙计,非常感谢@Igonato 的回答!【参考方案6】:

如果您使用的是 python 3+,请尝试添加以下行

import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)

【讨论】:

【参考方案7】:

试试

from . import config

这样做是从同一文件夹级别导入。如果你直接尝试导入它假定它是一个从属

【讨论】:

【参考方案8】:

在项目根目录下设置PYTHONPATH环境变量。

考虑类 UNIX:

export PYTHONPATH=.

【讨论】:

这很有魅力!非常感谢。【参考方案9】:

您可以简单地将以下文件添加到您的测试目录中,然后 python 将在测试之前运行它

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

【讨论】:

这正是我想要的。感谢分享这个答案!!! 做这样的事情会产生一个 linter (pylint3) 错误。错误与此类似。 filename.py:12:0: C0413: Import "import abc.def.ghi.file_util as file_util" 应该放在模块的顶部(错误的导入位置) 优秀。 __init__ 文件的这些内容适用于 Python 3.6.6【参考方案10】:

在调用模块之前声明正确的 sys.path 列表:

import os, sys

#'/home/user/example/parent/child'
current_path = os.path.abspath('.')

#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)

sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')

【讨论】:

【参考方案11】:

试过你的例子

from . import config

收到以下系统错误: /usr/bin/python3.4 test.py 回溯(最近一次通话最后一次): 文件“test.py”,第 1 行,在 从 。 import configSystemError: Parent module '' not loaded, cannot perform relative import


这对我有用:

import config
print('debug=%s'%config.debug)

>>>debug=True

用 Python 测试:3.4.2 - PyCharm 2016.3.2


除此 PyCharm 之外,您还可以导入此名称。 您必须点击config 并出现一个帮助图标

【讨论】:

【参考方案12】:

设置 PYTHONPATH 也可以帮助解决这个问题。

这是如何在 Windows 上完成的

set PYTHONPATH=.

【讨论】:

将 PYTHONPATH 设置为主代码目录为我解决了这个问题! 也适用于 Linux。导出 PYTHONPATH=.【参考方案13】:

我想通了。非常令人沮丧,尤其是来自python2。

无论是相对的还是绝对的,都必须在模块中添加.

我创建的目录设置如下。

/main.py
--/lib
  --/__init__.py
  --/mody.py
  --/modx.py

modx.py

def does_something():
    return "I gave you this string."

mod.py

from modx import does_something

def loaded():
    string = does_something()
    print(string)

main.py

from lib import mody

mody.loaded()

当我执行 main 时,会发生这种情况

$ python main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from lib import mody
  File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
    from modx import does_something
ImportError: No module named 'modx'

我跑了2to3,核心输出是这样的

RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
@@ -1,4 +1,4 @@
-from modx import does_something
+from .modx import does_something

 def loaded():
     string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py

我不得不修改 mody.py 的 import 语句来修复它

try:
    from modx import does_something
except ImportError:
    from .modx import does_something


def loaded():
    string = does_something()
    print(string)

然后我再次运行 main.py 并得到了预期的输出

$ python main.py
I gave you this string.

最后,只是为了清理它并使其在 2 和 3 之间可移植。

from __future__ import absolute_import
from .modx import does_something

【讨论】:

值得注意的是,try/except 加载程序是在这里工作的真正要素(因为有些人需要使用 try:scripts.modxexcept: modx),它为我解决了这个问题。 在导入时尝试/除外是丑陋的。我希望有更好的解决方案。 你必须添加一个 .到模块,不管它是相对的还是绝对的 这不是很准确。如果你使用点,那么它就变成了相对导入。 非常感谢!这个点 (.) 对我来说是真正的问题 =) 我正在使用一个名为 generateDS 的库,并在模块名称处添加一个点,并在 2021 年解决问题!谢谢!【参考方案14】:

正如原始帖子的 cmets 中所述,这似乎是我使用的 python 解释器的问题,无论出于何种原因,而不是 python 脚本有问题。我从 python.org 从 WinPython 包切换到官方 python 3.6,它工作得很好。谢谢大家的帮助:)

【讨论】:

嗯讨厌这么说,但同样的事情也发生在我身上。重建环境解决了这个问题。就我而言,我在运行测试时遇到了这个错误。在相同的环境中,尝试导入相同的模块。重新创建环境将它们全部修复(相同的 python 版本 3.6) 不同的 IDE 有不同的方式处理项目源文件(视图、模块、模板等)的路径。如果您的项目结构和编码正确,那么它应该适用于所有(标准)IDE . WinPython 等流行的 IDE 出现问题意味着问题确实来自您的项目。如上所述,问题是 user3159377 的“您必须向模块添加 .”,这应该是公认的答案。【参考方案15】:

此示例适用于 Python 3.6。

我建议转到 PyCharm 中的Run -&gt; Edit Configurations,删除那里的所有条目,然后尝试再次通过 PyCharm 运行代码。

如果这不起作用,请检查您的项目解释器(设置 -> 项目解释器)并运行配置默认值(运行 -> 编辑配置...)。

【讨论】:

以上是关于相对导入 - ModuleNotFoundError:没有名为 x 的模块的主要内容,如果未能解决你的问题,请参考以下文章

相对导入

Python中的相对导入语法

详解Python中的相对导入和绝对导入

Python 包内的导入问题(绝对导入和相对导入)

模块之相对路径导入

Python中的“尝试相对导入超出***包”错误意味着啥?