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

bli*_*ann 117 python package python-import python-3.x relative-import

这是我第一次真正坐下来尝试python 3,似乎失败了.我有以下两个文件:

  1. test.py
  2. config.py

config.py中定义了一些函数以及一些变量.我把它剥离到以下内容:

在此输入图像描述

但是,我收到以下错误:

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

我知道py3约定是使用绝对导入:

from . import config
Run Code Online (Sandbox Code Playgroud)

但是,这会导致以下错误:

ImportError: cannot import name 'config'
Run Code Online (Sandbox Code Playgroud)

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

Igo*_*ato 127

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

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

相对导入 - 相对于当前模块导入某些内容,必须是包的一部分

如果您以完全相同的方式运行两个变体,其中一个应该可以工作.无论如何,这里有一个例子可以帮助你理解发生了什么,让我们添加另一个main.py文件,整个目录结构如下:

.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py
Run Code Online (Sandbox Code Playgroud)

让我们更新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
Run Code Online (Sandbox Code Playgroud)

我们先运行test.py:

$ python ryan/test.py
__main__
Relative import failed
True
Run Code Online (Sandbox Code Playgroud)

这里的"测试" __main__模块,不知道属于什么包.但是import config应该可以工作,因为该ryan文件夹将被添加到sys.path中.

让我们运行main.py:

$ python main.py
ryan.test
True
Absolute import failed
Run Code Online (Sandbox Code Playgroud)

这里测试是在"ryan"包中,可以执行相对导入.import config失败,因为Python 3中不允许隐式相对导入.

希望这有帮助.

PS:如果你坚持使用Python 3,就不再需要__init__.py文件了.

  • *“如果您坚持使用 Python 3,则不再需要 `__init__.py` 文件。”* 相反,如果我们希望一个包在 2 和 3 中都能工作,您能描述一下吗?看看过时的 2009 年 [`__init__.py` 是什么?](/sf/ask/31379001/) 及其最重要的 -赞成的答案 *“这是包裹的一部分”*。我们需要开始强调区别 *"regular package [old, pre-3.3]"* vs *"namespace package [3.3+]"* 无处不在,而且经常。 (3认同)
  • 我能做些什么来让绝对进口始终有效吗?比如,在`/ some/path/my_module/__ init __.py`里面调用`sys.path.append('/ some/path/my_module')`? (2认同)
  • @JamesT。是的,在运行时修改sys.path很常见(https://github.com/search?q=sys.path.append&type=Code&utf8=%E2%9C%93)。您还可以设置PYTHONPATH环境变量。 (2认同)
  • “如果您坚持使用Python 3,`__init __。py`文件将不再需要。” 有趣。您能详细说明一下吗?我的印象是,包解析机制在2到3之间没有太大变化。 (2认同)

小智 46

我想到了.非常令人沮丧,特别是来自python2.

您必须向.模块添加一个,无论它是相对的还是绝对的.

我创建了目录设置如下.

/main.py
--/lib
  --/__init__.py
  --/mody.py
  --/modx.py
Run Code Online (Sandbox Code Playgroud)

modx.py

def does_something():
    return "I gave you this string."
Run Code Online (Sandbox Code Playgroud)

mody.py

from modx import does_something

def loaded():
    string = does_something()
    print(string)
Run Code Online (Sandbox Code Playgroud)

main.py

from lib import mody

mody.loaded()
Run Code Online (Sandbox Code Playgroud)

当我执行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'
Run Code Online (Sandbox Code Playgroud)

我跑了2到3,核心输出就是这个

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
Run Code Online (Sandbox Code Playgroud)

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

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


def loaded():
    string = does_something()
    print(string)
Run Code Online (Sandbox Code Playgroud)

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

$ python main.py
I gave you this string.
Run Code Online (Sandbox Code Playgroud)

最后,只需将其清理干净并使其在2到3之间便携.

from __future__ import absolute_import
from .modx import does_something
Run Code Online (Sandbox Code Playgroud)

  • _您必须添加一个 . 到模块,无论是相对的还是绝对的_这不太准确。如果使用点,那么它就成为相对导入。 (3认同)
  • 值得注意的是,“try/ except”加载过程是在这里起作用的真正成分(因为有些人需要使用“try:scripts.modx”和“ except:modx”),并且是为我解决这个问题的原因。 (2认同)

小智 22

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

以下是如何在Windows上完成的

set PYTHONPATH=.

  • 将PYTHONPATH设置为主代码目录为我解决了问题! (4认同)
  • 也适用于 Linux。导出 PYTHONPATH=. (3认同)

Viv*_*arg 17

如果您使用的是 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)
Run Code Online (Sandbox Code Playgroud)

  • 相同答案的另一个版本,这也有效: `sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))` 这里省略了一些内容,例如: `os.path .abspath` 或 `os.path.realpath` (3认同)

sto*_*vfl 13

试试你的榜样

from . import config
Run Code Online (Sandbox Code Playgroud)

得到以下SystemError:
/usr/bin/python3.4 test.py
Traceback(最近一次调用最后一次):
文件"test.py",第1行,
来自.import config
SystemError:父模块''未加载,无法执行相对导入


这对我有用:

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

>>>debug=True
Run Code Online (Sandbox Code Playgroud)

用Python测试:3.4.2 - PyCharm 2016.3.2


除此之外,PyCharm还提供了导入此名称的功能.
您可以单击config并显示帮助图标. 在此输入图像描述


Gio*_*ous 10

您必须将模块的路径附加到PYTHONPATH

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢@Giorgos!当您尝试在Docker映像中设置根目录时尤其如此。 (2认同)

man*_*uza 9

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

考虑类 UNIX:

export PYTHONPATH=.
Run Code Online (Sandbox Code Playgroud)


Vin*_*ane 8

您只需将以下文件添加到测试目录中,然后python将在测试之前运行它

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
Run Code Online (Sandbox Code Playgroud)


Hoa*_*ell 7

在调用模块之前声明正确的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')
Run Code Online (Sandbox Code Playgroud)


小智 6

尝试

from . import config
Run Code Online (Sandbox Code Playgroud)

其作用是从同一文件夹级别导入。如果您直接尝试导入,它会假设它是从属的


Geo*_*lou 6

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

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

export PYTHONPATH=.
python my_module/__main__.py
Run Code Online (Sandbox Code Playgroud)


bli*_*ann 3

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

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