相对导入 - 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.modx
和 except: 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 -> Edit Configurations
,删除那里的所有条目,然后尝试再次通过 PyCharm 运行代码。
如果这不起作用,请检查您的项目解释器(设置 -> 项目解释器)并运行配置默认值(运行 -> 编辑配置...)。
【讨论】:
以上是关于相对导入 - ModuleNotFoundError:没有名为 x 的模块的主要内容,如果未能解决你的问题,请参考以下文章