У меня есть структура проекта с голыми костями с в основном пустыми файлами 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
Любые подсказки будут высоко оценены.
Вы можете присоединиться к пути внешнего пакета внутри пути вашего источника для импорта относительного модуля:
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
.
Вы все равно получите ImportError: attempted relative import with no known parent package
, потому что при выполнении module1.py
атрибут __package__
будет None
.
Это объясняется в PEP 336. Обратите внимание на часть, в которой говорится: «Чтобы разрешить относительный импорт, когда модуль выполняется напрямую, перед первым оператором относительного импорта потребуется шаблон, подобный следующему [...] Обратите внимание, что этого шаблона достаточно, только если пакет верхнего уровня уже доступен через sys.path. Для работы прямого выполнения потребуется дополнительный код, управляющий sys.path [...]».
Спасибо @Диего! Это дает мне более фундаментальное понимание того, что здесь происходит.
Относительный импорт не сработал, потому что module1.py не мог заглянуть в свою родительскую папку для получения дополнительных пакетов при прямом выполнении.
Для правильного вызова требовался параметр -m для обозначения того, что module1 был модулем внутри пакета. Моему терминалу также нужно было перейти на один каталог вверх:
PS C:\...\"parent of project folder"> python -m project.package1.module1
Также необходимо изменить module1.py:
from ..package2.module2 import function2
Это немного более подробно, чем я надеялся, что это будет. Я читал эту статью/учебник по относительному импорту: realpython.com/absolute-vs-relative-python-imports Эта статья показала, что это можно сделать без указания путей. Как вы думаете, возможна ли такая авторская стратегия?