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


178

这是我第一次真正坐下来尝试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'

因此,我对此无所适从……任何帮助将不胜感激。:)


我无法重现该错误,如何执行此代码?
科波菲尔(Copperfield)

2
我使用python和as附带的闲置函数来执行它python test.py,并且工作得很好。我没有pyCharm,但可能是pyCharm的某些错误配置导致了问题
Copperfield

1
很奇怪。我正在使用WinPython-只需从python.org下载vanilla Python 3.6,即可正常工作。没想到要检查口译员!谢谢!
闪电战

1
我的猜测是PYTHONPATH正在发生一些时髦的事情。检查您的IDE设置和/或系统环境变量。
马丁·图尔诺伊

1
我也有同样的问题。不是pycharm!是python3。它在python2中有效,但是在使用python3时,您会看到此错误!非常沮丧

Answers:


163

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

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

希望这会有所帮助。

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


3
我有什么办法可以使绝对导入始终有效?像,sys.path.append('/some/path/my_module')在里面打电话/some/path/my_module/__init__.py
James T.

4
@JamesT。是的,sys.path在运行时进行修改是很常见的(github.com/…)。您还可以设置PYTHONPATH环境变量。
伊戈纳托

6
“如果您坚持使用Python 3,则不再需要__init__.py文件。” 有趣。您能详细说明一下吗?我的印象是,包解析机制在2到3之间没有太大变化
Kevin

2
“如果您坚持使用Python 3,则不再需要__init__.py文件。” 反过来说,如果我们要一个软件包同时在2和3中工作,您能描述一下吗?并看一下过时的2009版是什么意思__init__.py及其最受好评的答案“它是包装的一部分”。我们需要开始在各处(经常是)强调“常规软件包[3.3之前的旧版本]”“命名空间软件包[3.3+]”之间的区别
smci

61

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

.无论模块是相对的还是绝对的,都必须向模块添加a 。

我创建目录设置如下。

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

修改器

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

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

1
值得一提的是,try/except加载过程是在这里起作用的真正要素(因为有些人将需要使用try:scripts.modxexcept: modx),并且正是它为我解决了这个问题。
Justapigeon

40

设置PYTHONPATH也可以解决此问题。

这是在Windows上可以完成的方法

set PYTHONPATH=.


11
将PYTHONPATH设置为主代码目录为我解决了这个问题!
极客

1
在Linux中也可以使用。导出PYTHONPATH =。
rjdkolb

29

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


对于UNIX(Linux,OSX等)

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

对于Windows

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

4
非常感谢@Giorgos!当您尝试在Docker映像中设置根目录时尤其如此。
托尼·弗雷泽

15

试过你的例子

from . import config

得到了以下SystemError:
/usr/bin/python3.4 test.py
Traceback(最近一次调用最近):
文件“ test.py”,第1行,位于
中。导入配置
SystemError:父模块“”未加载,无法执行相对导入


这对我有用:

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

>>>debug=True

使用Python:3.4.2测试-PyCharm 2016.3.2


除了此PyCharm,您还可以导入该名称
您必须单击,config然后出现帮助图标在此处输入图片说明


11

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

__init__.py file

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

这正是我一直在寻找的东西。感谢您分享这个答案!!!
Mayur

这样做会产生皮棉(pylint3)错误。错误与此类似。filename.py:12:0:C0413:导入“ import abc.def.ghi.file_util as file_util”应放在模块顶部(错误的导入位置)
Sharad

6

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

考虑类UNIX:

export PYTHONPATH=.

4

此示例在Python 3.6上有效。

我建议进入Run -> Edit ConfigurationsPyCharm,删除那里的所有条目,然后尝试再次通过PyCharm运行代码。

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


4

在调用模块之前,声明正确的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')

1

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


1
嗯,我不想这么说,但同样的事情发生在我身上。重新创建环境可解决此问题。就我而言,运行测试时出现此错误。在相同的环境中,尝试导入相同的模块有效。重新创建环境修复了所有问题(相同的Python版本3.6)
naoko

1
不同的IDE处理项目源文件(视图,模块,模板等)的路径有不同的方式,特别是如果项目的结构和编码正确,则它应适用于所有(标准)IDE。诸如WinPython之类的流行IDE出现问题意味着问题确实出在您的项目中。如上所述,问题是user3159377的“您必须在模块中添加一个。”这应该是公认的答案。
winux

1

如果您使用的是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)

0

尝试

from . import config

这是从同一文件夹级别导入的。如果您直接尝试导入,则假定它是下属

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.