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

Добавить текущий каталог в каталог среды