Ответ 1
Лучшим решением для вашей проблемы является размещение пакета1 в отдельном пакете. Конечно, тогда он не может импортировать пакет2, но опять же, если он многократно используется, зачем он?
Импорт Python сводит меня с ума (мой опыт с импортом python когда-то совсем не соответствует идиоме "Явный лучше, чем неявный":():
[app]
start.py
from package1 import module1
[package1]
__init__.py
print('Init package1')
module1.py
print('Init package1.module1')
from . import module2
module2.py
print('Init package1.module2')
import sys, pprint
pprint.pprint(sys.modules)
from . import module1
Я получаю:
[email protected]:~/Desktop/app2$ python3 start.py
Init package1
Init package1.module1
Init package1.module2
{'__main__': <module '__main__' from 'start.py'>,
...
'package1': <module 'package1' from '/home/vic/Desktop/app2/package1/__init__.py'>,
'package1.module1': <module 'package1.module1' from '/home/vic/Desktop/app2/package1/module1.py'>,
'package1.module2': <module 'package1.module2' from '/home/vic/Desktop/app2/package1/module2.py'>,
...
Traceback (most recent call last):
File "start.py", line 3, in <module>
from package1 import module1
File "/home/vic/Desktop/app2/package1/module1.py", line 3, in <module>
from . import module2
File "/home/vic/Desktop/app2/package1/module2.py", line 5, in <module>
from . import module1
ImportError: cannot import name module1
[email protected]:~/Desktop/app2$
import package1.module1
работает, но я хочу использовать from . import module1
, потому что хочу сделать package1
переносимым для других приложений, поэтому я хочу использовать относительные пути.
Я использую python 3.
Мне нужен круговой импорт. Функция в модуле 1 утверждает, что один из ее параметров является экземпляром класса, определенного в модуле 2 и наоборот.
Другими словами:
sys.modules
содержит 'package1.module1': <module 'package1.module1' from '/home/vic/Desktop/app2/package1/module1.py'>
. Я хочу получить ссылку на него в форме from . import module1
, но он пытается получить имя, а не пакет, например, в случае import package1.module1
(который отлично работает). Я пробовал import .module1 as m1
- но это синтаксическая ошибка.
Кроме того, from . import module2
в module1
работает отлично, но from . import module1
в module2
не работает...
UPDATE:
Этот хак работает (но я ищу "официальный" способ):
print('Init package1.module2')
import sys, pprint
pprint.pprint(sys.modules)
#from . import module1
parent_module_name = __name__.rpartition('.')[0]
module1 = sys.modules[parent_module_name + '.module1']
Лучшим решением для вашей проблемы является размещение пакета1 в отдельном пакете. Конечно, тогда он не может импортировать пакет2, но опять же, если он многократно используется, зачем он?
Следует избегать циркулярного импорта, см. также этот ответ на соответствующий вопрос или эта статья об 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
(так как он имеет тот же путь импорта).
Или даже лучше, вы вообще избавляетесь от циклического импорта. В целом это признак того, что ваша структура приложения не так хороша, если у вас есть круглые ссылки.
(Надеюсь, мое объяснение имеет какой-то смысл, мне уже было трудно писать его, но общая идея должна быть ясной, надеюсь...)
В ответ на ваше обновление; то, что вы делаете, заключается в том, что вы используете полное имя пакета, чтобы получить ссылку на модуль. Это эквивалентно (но гораздо более сложному) первому возможному варианту, чтобы заставить его работать; вы используете абсолютный импорт, используя тот же путь импорта, что и в start.py
.
Ваше обновление эмулирует то, что делает абсолютный импорт: import package1.module1
, если вы делаете это, пока module1
импортируется. Если вы хотите использовать имя динамического родительского пакета, то для импорта module1
в module2.py
:
import importlib
module1 = importlib.import_module('.module1', __package__)
Мне нужен круговой импорт. Функция в модуле 1 утверждает, что одна из ее Параметр - это экземпляр класса, определенного в модуле 2 и наоборот.
Вы можете перенести один класс на отдельный модуль, чтобы разрешить циклическую зависимость или сделать импорт на уровне функции, если вы не хотите использовать абсолютный импорт.
.
├── start.py
# from package1 import module1
└── package1
├── __init__.py
# print("Init package1")
# from . import module1, module2
├── c1.py
# print("Init package1.c1")
# class C1:
# pass
├── module1.py
# print("Init package1.module1")
# from .c1 import C1
# from .module2 import C2
└── module2.py
# print("Init package1.module2")
# from .c1 import C1
# class C2:
# pass
# def f():
# from .module1 import C1
Init package1
Init package1.module1
Init package1.c1
Init package1.module2
Другой вариант, который может быть проще, чем рефакторинг c1.py
, заключается в объединении module{1,2}.py
в один common.py
. module{1,2}.py
сделать импорт из common
в этом случае.
module2.py
import module1
Работает тоже.
Принятый ответ Циркулярная зависимость импорта в Python дает хороший результат:
Если a зависит от c и c зависит от a, они не являются фактически одной и той же единицей, то?
Вы должны действительно изучить, почему вы разделили a и c на два пакета, потому что либо у вас есть код, который вы должны разделить на другой пакет (чтобы они зависели от этого нового пакета, но не друг от друга), или вы должны объединить их в один пакет.
— Лассе В. Карлсен ♦
Возможно, вам стоит рассмотреть возможность размещения их в одном модуле.:)
Сегодня я столкнулся с этой же проблемой, и, похоже, это действительно сломано в python3.4, но работает в python3.5.
changelog имеет запись:
Циркулярный импорт, включающий относительный импорт, теперь поддерживается. (Бретт Кэннон и Антуан Питроу в bpo-17636).
Просматривая ошибку, кажется, что это не столько фиксированное buf, сколько новая функция в способе импорта. Ссылаясь на poke answer above, он показывает, что from . import foo
означает загрузить __init__.py
и получить foo
от него (возможно, из неявно загруженного списка подмодулей). Поскольку python3.5, from . import foo
будет делать то же самое, но если foo
недоступен в качестве атрибута, он будет возвращаться к просмотру списков загруженных модулей (sys.modules
), чтобы увидеть, если он уже присутствует там, который фиксирует этот конкретный случай. Я не на 100% уверен, что правильно представил, как это работает.
Убедитесь, что ваш package1
- это папка. Создайте класс в __init__.py
- скажем class1
. Включите свою логику в метод под class1
- скажем method1
.
Теперь напишите следующий код -
from .package1 import class1
class1.method1()
Это был мой способ разрешить это. Подводя итог, ваш корневой каталог .
, поэтому напишите инструкцию import
, используя обозначения .
, например. from .package
или from app.package
.