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

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

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

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

This is the first time I’ve really sat down and tried python 3, and seem to be failing miserably. I have the following two files:

  1. test.py
  2. config.py

config.py has a few functions defined in it as well as a few variables. I’ve stripped it down to the following:

config.py

debug = True

test.py

import config
print (config.debug)

I also have an __init__.py

However, I’m getting the following error:

ModuleNotFoundError: No module named 'config'

I’m aware that the py3 convention is to use absolute imports:

from . import config

However, this leads to the following error:

ImportError: cannot import name 'config'

So I’m at a loss as to what to do here… Any help is greatly appreciated. :)


回答 0

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文件中不再需要。

TL;DR: You can’t do relative imports from the file you execute since __main__ module is not a part of a package.

Absolute imports – import something available on sys.path

Relative imports – import something relative to the current module, must be a part of a package

If you’re running both variants in exactly the same way, one of them should work. Here is an example that should help you understand what’s going on. Let’s add another main.py file with the overall directory structure like this:

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

And let’s update test.py to see what’s going on:

# 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

Let’s run test.py first:

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

Here “test” is the __main__ module and doesn’t know anything about belonging to a package. However import config should work, since the ryan folder will be added to sys.path.

Let’s run main.py instead:

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

And here test is inside of the “ryan” package and can perform relative imports. import config fails since implicit relative imports are not allowed in Python 3.

Hope this helped.

P.S.: If you’re sticking with Python 3 there is no more need for __init__.py files.


回答 1

我想到了。非常令人沮丧,尤其是来自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

I figured it out. Very frustrating, especially coming from python2.

You have to add a . to the module, regardless of whether or not it is relative or absolute.

I created the directory setup as follows.

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

modx.py

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

mody.py

from modx import does_something

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

main.py

from lib import mody

mody.loaded()

when I execute main, this is what happens

$ 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'

I ran 2to3, and the core output was this

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

I had to modify mody.py’s import statement to fix it

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


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

Then I ran main.py again and got the expected output

$ python main.py
I gave you this string.

Lastly, just to clean it up and make it portable between 2 and 3.

from __future__ import absolute_import
from .modx import does_something

回答 2

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

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

set PYTHONPATH=.

Setting PYTHONPATH can also help with this problem.

Here is how it can be done on Windows

set PYTHONPATH=.


回答 3

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


对于UNIX(Linux,OSX等)

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

对于Windows

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

You have to append your project’s path to PYTHONPATH and make sure to use absolute imports.


For UNIX (Linux, OSX, …)

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

For Windows

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

Absolute imports

Assuming that we have the following project structure,

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

just make sure to reference each import starting from the project’s root directory. For instance,

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

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

回答 4

试过你的例子

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然后出现帮助图标

Tried your example

from . import config

got the following SystemError:
/usr/bin/python3.4 test.py
Traceback (most recent call last):
File “test.py”, line 1, in
from . import config
SystemError: Parent module ” not loaded, cannot perform relative import


This will work for me:

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

>>>debug=True

Tested with Python:3.4.2 – PyCharm 2016.3.2


Beside this PyCharm offers you to Import this name.
You hav to click on config and a help icon appears.


回答 5

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

__init__.py file

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

You can simply add following file to your tests directory, and then python will run it before the tests

__init__.py file

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

回答 6

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

考虑类UNIX:

export PYTHONPATH=.

Set PYTHONPATH environment variable in root project directory.

Considering UNIX-like:

export PYTHONPATH=.

回答 7

此示例在Python 3.6上有效。

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

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

This example works on Python 3.6.

I suggest going to Run -> Edit Configurations in PyCharm, deleting any entries there, and trying to run the code through PyCharm again.

If that doesn’t work, check your project interpreter (Settings -> Project Interpreter) and run configuration defaults (Run -> Edit Configurations…).


回答 8

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

Declare correct sys.path list before you call module:

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')

回答 9

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

As was stated in the comments to the original post, this seemed to be an issue with the python interpreter I was using for whatever reason, and not something wrong with the python scripts. I switched over from the WinPython bundle to the official python 3.6 from python.org and it worked just fine. thanks for the help everyone :)


回答 10

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

If you are using python 3+ then try adding below lines

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)

回答 11

尝试

from . import config

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

Try

from . import config

What that does is import from the same folder level. If you directly try to import it assumes it’s a subordinate