Как решить: попытка относительного импорта без известного родительского пакета

У меня есть структура проекта с голыми костями с в основном пустыми файлами python для тестирования концепции из онлайн-учебника:

project
   |--package1
   |     |--__init__.py
   |     |--module1.py
   |
   |--package2
   |     |--__init__.py
   |     |--module2.py
   |
   |--__init__.py

модуль1.py:

from .package2.module2 import function2

модуль2.py:

def function2():
    return 0

Запуск module1.py напрямую приводит к этой ошибке:

Traceback (most recent call last):
  File "c:\"blahblahblah"\project\package1\module1.py", line 1, in <module>
    from .package2.module2 import function2
ImportError: attempted relative import with no known parent package

Я попытался уменьшить сложность проблемы, поместив module2.py в саму папку проекта и изменив импорт, как предполагает мой учебник (из .module2 import function2), но это дает ту же ошибку.

примечание: у меня сложилось впечатление, что файлы инициализации не нужны для моей версии Python, но я добавил их, чтобы охватить все мои базы.

Python версии 3.9.1

Любые подсказки будут высоко оценены.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
5
0
8 792
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете присоединиться к пути внешнего пакета внутри пути вашего источника для импорта относительного модуля:

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

Я думаю, после этого вы можете напрямую сделать:

from package2.module2 import function2

Когда вы выполняете сценарий Python, конкретный каталог, в котором находится сценарий, добавляется к пути, но не его родительский каталог.

Вам нужно будет добавить корневой каталог к ​​пути, чтобы Python мог найти package2.

Для этого вы можете использовать модуль pathlib (Python 3.4 или выше), изменив module1.py таким образом:

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from package2.module2 import function2

Метод Path.resolve() возвращает абсолютный путь к файлу, а с помощью parent.parent вы получаете родительский каталог module1.py (корневой каталог). Поэтому Python теперь сможет найти package2.

Кроме того, поскольку вы получаете абсолютный путь, импорт будет работать независимо от того, выполняется ли скрипт из каталога project или из package1.

Это немного более подробно, чем я надеялся, что это будет. Я читал эту статью/учебник по относительному импорту: realpython.com/absolute-vs-relative-python-imports Эта статья показала, что это можно сделать без указания путей. Как вы думаете, возможна ли такая авторская стратегия?

Micahstuh 04.01.2021 14:34

Вы все равно получите ImportError: attempted relative import with no known parent package, потому что при выполнении module1.py атрибут __package__ будет None.

Diego Miguel 04.01.2021 19:31

Это объясняется в PEP 336. Обратите внимание на часть, в которой говорится: «Чтобы разрешить относительный импорт, когда модуль выполняется напрямую, перед первым оператором относительного импорта потребуется шаблон, подобный следующему [...] Обратите внимание, что этого шаблона достаточно, только если пакет верхнего уровня уже доступен через sys.path. Для работы прямого выполнения потребуется дополнительный код, управляющий sys.path [...]».

Diego Miguel 04.01.2021 19:31

Спасибо @Диего! Это дает мне более фундаментальное понимание того, что здесь происходит.

Micahstuh 04.01.2021 20:59
Ответ принят как подходящий

Относительный импорт не сработал, потому что module1.py не мог заглянуть в свою родительскую папку для получения дополнительных пакетов при прямом выполнении.

Для правильного вызова требовался параметр -m для обозначения того, что module1 был модулем внутри пакета. Моему терминалу также нужно было перейти на один каталог вверх:

PS C:\...\"parent of project folder"> python -m project.package1.module1

Также необходимо изменить module1.py:

from ..package2.module2 import function2

Другие вопросы по теме