Циркулярный импорт обычно следует избегать, см. Также этот ответ на связанный вопрос или эту статью на effbot.org .
В этом случае проблемаВы импортируете from .
, где .
- текущий пакет.Таким образом, все ваши from . import X
импорты проходят через пакет __init__.py
.
. Вы можете сделать вашу проблему более заметной, если явно импортируете свои модули в __init__.py
и дадите им другое имя (и отрегулируетедругие, конечно же, используют эти имена):
print('Init package1')
from . import module1 as m1
from . import module2 as m2
Теперь, когда вы импортируете m1
в start.py
, пакет сначала инициализирует m1
и доходит до строки from . import m2
.На этом этапе в __init__.py
нет известных m2
, поэтому вы получаете ошибку импорта.Если вы переключите операторы импорта в __init__.py
(то есть сначала загрузите m2
), то в m2
он найдет строку from . import m1
, которая завершается ошибкой по той же причине, что и раньше.
ЕслиВы явно не импортируете модули в __init__.py
, что-то подобное все еще происходит в фоновом режиме.Разница в том, что вы получаете менее плоскую структуру (поскольку импорт больше не начинается только из пакета).Таким образом, module1
и module2
запускаются, и вы получаете соответствующие отпечатки инициализации.
Чтобы это работало, вы можете выполнить абсолютный импорт в module2
.Таким образом, вы можете избежать того, что пакет должен сначала разрешить все, и заставить его повторно использовать импорт из start.py
(так как он имеет тот же путь импорта).
Или, что еще лучше, вы избавитесь от циклическогоимпорт вообще.Как правило, это признак того, что структура вашего приложения не так хороша, если у вас есть циклические ссылки.
(надеюсь, мое объяснение имеет какой-то смысл, у меня уже были трудности при его написании, но общая идея должна быть ясной, янадеюсь ...)
edit
В ответ на ваше обновление;то, что вы делаете, это то, что вы используете полное имя пакета, чтобы получить ссылку на модуль.Это эквивалентно (но намного сложнее) первому возможному варианту заставить его работать;Вы используете абсолютный импорт, используя тот же путь импорта, что и в start.py
.