Относительный импорт - ModuleNotFoundError: нет модуля с именем x

179

Это первый раз, когда я по-настоящему сел и попробовал 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'

Так что я в растерянности относительно того, что делать здесь ... Любая помощь очень ценится. :)

blitzmann
источник
Я не могу воспроизвести ошибку, как вы выполняете этот код?
Копперфильд
2
Я выполняю его с простоями, которые поставляются с Python, а также как python test.py, и он прекрасно работает. У меня нет pyCharm, но, возможно, есть какая-то плохая конфигурация pyCharm, которая вызывает проблему
Copperfield
1
Очень странно. Я использую WinPython - просто скачайте vanilla Python 3.6 с python.org, и он отлично работает. Никогда не думал проверять переводчика! Спасибо!
блицман
1
Я предполагаю, что с PYTHONPATH происходит что-то интересное. Проверьте настройки IDE и / или системные переменные окружения.
Мартин Турной
1
У меня точно такая же проблема. Это не пичарм! Это python3. Это работает в python2, но при использовании python3 вы видите эту ошибку! очень расстраивает

Ответы:

164

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

И здесь тест находится внутри пакета «Райан» и может выполнять относительный импорт. import configтерпит неудачу, так как неявный относительный импорт не разрешен в Python 3.

Надеюсь, это помогло.

PS: если вы придерживаетесь Python 3, больше нет необходимости в __init__.pyфайлах.

Igonato
источник
3
Что я могу сделать, чтобы абсолютный импорт всегда работал? Мол, позвони sys.path.append('/some/path/my_module')внутрь /some/path/my_module/__init__.py?
Джеймс Т.
4
@JamesT. Да, это довольно часто, чтобы изменить sys.pathво время выполнения ( github.com/… ). Вы также можете установить переменную окружения PYTHONPATH.
Игонато
6
«если вы придерживаетесь Python 3, вам больше не нужны __init__.pyфайлы». Интересный. Вы можете остановиться на этом? У меня сложилось впечатление, что механизм разрешения пакетов не сильно изменился между 2 и 3.
Кевин
2
«если вы придерживаетесь Python 3, вам больше не нужны __init__.pyфайлы». И наоборот, можете ли вы описать вещи, если мы хотим, чтобы пакет работал как в 2, так и в 3? И посмотрите на печально устаревший 2009 год. Для чего __init__.py? и его самый высокооплачиваемый ответ «Это часть пакета» . Нам нужно начать подчеркивать различие «обычный пакет [старый, до 3.3]« vs »пакет пространства имен [3.3+]» везде и часто.
smci
61

Я понял. Очень расстраивает, особенно с python2.

Вы должны добавить .к модулю, независимо от того, является ли он относительным или абсолютным.

Я создал каталог установки следующим образом.

/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()

когда я выполняю основной, это то, что происходит

$ 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, чтобы исправить это

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.modxи except: 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! Это особенно верно, когда вы пытаетесь установить корневой каталог в образе докера.
Тони Фрейзер
15

Попробовал твой пример

from . import config

получил следующую ошибку SystemError:
/usr/bin/python3.4 test.py
Traceback (последний вызов был последним):
файл "test.py", строка 1,
из from. import config
SystemError: Родительский модуль '' не загружен, не может выполнить относительный импорт


Это будет работать для меня:

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

>>>debug=True

Протестировано с Python: 3.4.2 - PyCharm 2016.3.2


Помимо этого PyCharm предлагает вам импортировать это имя .
Вы должны нажать, configи появится значок справки . введите описание изображения здесь

stovfl
источник
11

Вы можете просто добавить следующий файл в ваш каталог тестов, и тогда python запустит его перед тестами

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
Винод Рэйн
источник
Это именно то, что я искал. Спасибо, что поделились этим ответом !!!
Mayur
Выполнение чего-то подобного дает ошибку linter (pylint3). Ошибка похожа на эту. filename.py:12:0: C0413: Импорт "import abc.def.ghi.file_util as file_util" должен быть размещен в верхней части модуля (неправильная позиция импорта)
Sharad
6

Устанавливать PYTHONPATH переменную среды в корневом каталоге проекта.

Учитывая UNIX-подобный:

export PYTHONPATH=.
manasouza
источник
4

Этот пример работает на Python 3.6.

Я предлагаю пойти в Run -> Edit Configurations в PyCharm, удалить все записи и попытаться снова запустить код через 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')
HoangYell
источник
1

Как было указано в комментариях к исходному сообщению, это, похоже, проблема с интерпретатором Python, который я использовал по какой-либо причине, а не что-то не так с скриптами Python. Я переключился с пакета WinPython на официальный python 3.6 с python.org, и он работал просто отлично. Спасибо всем за помощь :)

blitzmann
источник
1
Хм, ненавижу это говорить, но то же самое случилось со мной. Воссоздание среды исправить проблему. В моем случае я получал эту ошибку при запуске тестов. В той же среде попытка импорта того же модуля сработала. Среда воссоздания исправила их все (та же версия Python 3.6)
naoko
1
Различные IDE имеют разные способы обработки путей, особенно для исходных файлов проекта (представлений, модулей, шаблонов и т. Д.). Если ваш проект структурирован и закодирован надлежащим образом, он должен работать для всех (стандартных) IDE. Проблемы с популярными IDE, такими как WinPython, означают, что проблема действительно исходит от вашего проекта. Как упоминалось выше, проблема заключается в том, что «пользователь должен добавить a.» В модуль 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

Что это делает, это импорт из того же уровня папки. Если вы пытаетесь импортировать напрямую, предполагается, что это подчиненный

Арни Бой
источник