Відносний імпорт - 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'

Тож я в занепокоєнні, що тут робити ... Будь-яка допомога дуже вдячна. :)


Я не можу відтворити помилку. Як виконати цей код?
Копперфілд

2
Я виконую його з простою, який поставляється з python, а також як python test.py, і він працює чудово. У мене немає pyCharm, але, можливо, це погана конфігурація pyCharm, яка викликає проблему
Copperfield

1
Дуже дивно. Я використовую WinPython - просто завантажте ваніль Python 3.6 з python.org, і це працює чудово. Ніколи не думав перевірити перекладача! Дякую!
бліцман

1
Я здогадуюсь, що з PYTHONPATH відбувається щось фанкі. Перевірте свої параметри IDE та / або змінні системного середовища.
Martin Tournoij

1
У мене така сама точна проблема. Це не піхарма! Це python3. Він працює в python2, але при використанні python3 ви бачите цю помилку! дуже засмучує.

Відповіді:


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

І ось тест знаходиться всередині пакету "Райан" і може здійснювати відносний імпорт. import configне вдається, оскільки неявний відносний імпорт у Python 3 не дозволений.

Сподіваюся, що це допомогло.

PS: якщо ви дотримуєтесь Python 3, у __init__.pyфайлах більше немає потреби .


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]" проти "пакет просторів імен [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), і було те , що вирішити це питання для мене.
Юстапійген

40

Налаштування PYTHONPATH також може допомогти у цій проблемі.

Ось як це можна зробити в Windows

set PYTHONPATH=.


11
встановлення PYTHONPATH в основний каталог коду вирішило проблему для мене!
Geek

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,
з. config config
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:10: C0413: Імпорт "імпорту abc.def.ghi.file_util як file_util" повинен бути розміщений у верхній частині модуля (неправильний імпорт-позиція)
Шарад

6

Встановити PYTHONPATH змінну середовища в каталозі кореневих проектів.

Беручи до уваги UNIX:

export PYTHONPATH=.

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

1

Як було сказано в коментарях до першої публікації, це, здавалося, було проблемою з інтерпретатором python, який я використовував з будь-якої причини, і не щось не так із сценаріями python. Я перейшов з пакета WinPython на офіційний python 3.6 з python.org, і він працював чудово. дякую за допомогу всім :)


1
Хм ненавиджу сказати це, але те саме трапилось і зі мною. Відтворення середовища вирішує проблему. У моєму випадку я отримував цю помилку під час запуску тестів. У тому ж середовищі працювала спроба імпорту одного модуля. Середовище відтворення зафіксувало їх усіх (та сама версія python 3.6)
naoko

1
У різних IDE є різні способи обробки траєкторії, спеціально для вихідних файлів проекту (представлення даних, модулів, шаблонів тощо). Якщо ваш проект структурований і кодується належним чином, він повинен працювати для всіх (стандартних) IDE. Проблеми з популярними IDE, такими як WinPython, означають, що проблема справді випливає з вашого проекту. Як згадувалося вище, проблема полягає в тому, що "Ви повинні додати модуль.
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

Це імпорт із того самого рівня папки. Якщо ви безпосередньо намагаєтеся імпортувати, це передбачає, що це підлеглий

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.