ModuleNotFoundError: нет модуля с именем '__main __. Xxxx'; '__main__' не является пакетом
В настоящее время пытаюсь работать в Python3 и использовать абсолютный импорт для импорта одного модуля в другой, но я получаю ошибку ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package
. Рассмотрим структуру этого проекта:
proj
__init__.py3 (empty)
moduleA.py3
moduleB.py3
moduleA.py3
from .moduleB import ModuleB
ModuleB.hello()
moduleB.py3
class ModuleB:
def hello():
print("hello world")
Затем запуск python3 moduleA.py3
выдает ошибку. Что нужно изменить здесь?
Ответы
Ответ 1
.moduleB
- относительный импорт. Относительная функция работает только тогда, когда родительский модуль сначала импортируется или загружается. Это означает, что вы должны импортировать proj
где-то в вашей текущей среде выполнения. Когда вы используете команду python3 moduleA.py3
, у него нет никакой возможности импортировать родительский модуль. Ты можешь:
-
from proj.moduleB import moduleB
OR - Вы можете создать другой скрипт, пусть скажем
run.py
, для вызова from proj import moduleA
Удачи вам в путешествии в удивительную страну Python.
Ответ 2
В дополнение к ответу md-sabuj-sarker, есть действительно хороший пример в документации по модулям Python.
Вот что говорят документы о ссылках внутри пакета:
Обратите внимание, что относительный импорт основан на имени текущего модуля. Поскольку имя основного модуля всегда "__main__"
, модули, предназначенные для использования в качестве основного модуля приложения Python, всегда должны использовать абсолютный импорт.
Если вы запустите python3 moduleA.py3
, moduleA
будет использован в качестве основного модуля, поэтому использование абсолютного импорта выглядит правильным решением.
Однако следует помнить, что этот абсолютный импорт (from package.module import something
) завершится неудачей, если по какой-то причине пакет содержит файл модуля с тем же именем, что и пакет (по крайней мере, на моем Python 3.7). Так, например, он потерпит неудачу, если у вас есть (на примере OP):
proj/
__init__.py (empty)
proj.py (same name as package)
moduleA.py
moduleB.py
в этом случае вы получите:
ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package
В качестве альтернативы, вы можете удалить .
в from .moduleB import
, как предложено здесь и здесь, что, похоже, работает, хотя мой PyCharm (2018.2.4) помечает это как " Неразрешенная ссылка "и не удается автозаполнить.
Ответ 3
Предисловие
Я разрабатываю проект, который на самом деле представляет собой пакет Python, который можно установить через pip, но он также предоставляет интерфейс командной строки. У меня нет проблем с запуском моего проекта после его установки с pip install .
, но, эй, кто делает это каждый раз после изменения чего-либо в одном из файлов проекта? Мне нужно было пройти через все это простым python mypackage/main.py
.
/my-project
- README.md
- setup.py
/mypackage
- __init__.py
- main.py
- common.py
Разные лица одной и той же проблемы
Я попытался импортировать несколько функций в main.py
из моего модуля common.py
. Я пробовал разные конфигурации, которые давали разные ошибки, и я хочу поделиться с вами своими наблюдениями и оставить небольшую заметку для будущего меня.
Относительный импорт
Первым, что я попробовал, был относительный импорт:
from .common import my_func
Я запустил свое приложение с простым: python mypackage/main.py
. К сожалению, это привело к следующей ошибке:
ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
Причиной этой проблемы является то, что main.py
был выполнен непосредственно командой python
, став тем самым основным модулем с именем __main__
. Если мы свяжем эту информацию с относительным импортом, который мы использовали, мы получим то, что имеем в сообщении об ошибке: __main__.common
. Это объясняется в документации по Python:
Обратите внимание, что относительный импорт основан на имени текущего модуля. Поскольку имя основного модуля всегда __main__
, модули, предназначенные для использования в качестве основного модуля приложения Python, всегда должны использовать абсолютный импорт.
Когда я установил пакет с pip install .
, а затем запустил его, он работал отлично. Я также смог импортировать модуль mypackage.main
в консоль Python. Так что, похоже, проблема только в его непосредственном запуске.
Абсолютный импорт
Давайте следуем советам из документации и изменим оператор импорта на что-то другое:
from common import my_func
Если мы сейчас попробуем запустить это, как и раньше: python mypackage/main.py
, то это будет работать как положено! Но есть предостережение, когда вы, как и я, разрабатываете что-то, что должно работать как отдельный инструмент командной строки после установки его с помощью pip. Я установил свой пакет с pip install .
, а затем попытался запустить его...
ModuleNotFoundError: No module named 'common'
Что еще хуже, когда я открыл консоль Python и попытался импортировать модуль main
вручную (import mypackage.main
), то я получил ту же ошибку, что и выше. Причина этого проста: common
больше не является относительным импортом, поэтому Python пытается найти его в установленных пакетах. У нас нет такого пакета, поэтому он не работает.
Решение с абсолютным импортом работает хорошо только тогда, когда вы создаете типичное приложение Python, которое выполняется с помощью команды python
.
Импорт с именем пакета
Существует также третья возможность импортировать модуль common
:
from mypackage.common import my_func
Это не очень отличается от подхода относительного импорта, если мы делаем это из контекста mypackage
. И снова попытка запустить это с python mypackage/main.py
заканчивается аналогично:
ModuleNotFoundError: No module named 'mypackage'
Как это может раздражать, переводчик прав, у вас не установлен такой пакет.
Решение
Для простых приложений Python
Просто используйте абсолютный импорт (без точки), и все будет хорошо.
Для устанавливаемых приложений Python в разработке
Используйте относительный импорт или импорт с именем пакета в начале, потому что он вам нужен, когда ваше приложение установлено. Когда дело доходит до запуска такого модуля в разработке, Python может быть выполнен с опцией -m
:
-m mod : run library module as a script (terminates option list)
Поэтому вместо python mypackage/main.py
сделайте это так: python -m mypackage.main
.
Ответ 4
Может быть, вы можете сделать это, прежде чем импортировать модуль:
moduleA.py3
import os
import re
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from moduleB import ModuleB
ModuleB.hello()
Добавить текущий каталог в каталог среды