Это шагает в опасный аргумент импорта кругов Питона, но, ИМХО, вы можете иметь отличный дизайн и по-прежнему нуждаться в круглых ссылках.
Итак, попробуйте этот подход:
thing.py:
class Thing(Base):
def action(self):
...do something with otherthing.Otherthing()...
import otherthing
subthing.py:
import thing
class Subthing(thing.Thing):
pass
otherthing.py:
class Otherthing(Base):
def action(self):
... do something with subthing.Subthing()...
import subthing
Есть пара вещей, происходящих здесь. Во-первых, некоторый фон.
Из-за того, как импортируются в Python, модуль, который находится в процессе импорта (но еще не полностью проанализирован), будет считаться уже импортированным, когда будут оцениваться будущие операции импорта в других модулях, ссылающихся на этот модуль. Таким образом, вы можете получить ссылку на символ в модуле, который все еще находится в середине анализа, и если синтаксический анализ не дошел до символа, который вам еще нужен, он не будет найден и будет метаться исключение.
Один из способов борьбы с этим - использовать «импорт хвоста». Целью этого метода является определение любых символов, которые могут потребоваться для других модулей, которые могут потребоваться до потенциального запуска импорта этих других модулей.
Еще один способ справиться с круговыми ссылками - переместить с from
на основе импорта в нормальный import
. Как это помогает? Когда у вас есть импорт стиля from
, целевой модуль будет импортирован, а затем символ, указанный в инструкции from, будет смотреться на объекте модуля прямо в этот момент.
С нормальным оператором import
поиск ссылки задерживается до тех пор, пока что-то не выполнит фактическую ссылку на атрибут модуля. Обычно это может быть сведено вниз к функции или методу, которые обычно не выполняются до тех пор, пока не будет завершен весь ваш импорт.
Случай, когда эти два метода не работают, - это когда у вас есть круговые ссылки в иерархии классов. Импорт должен быть представлен перед определением подкласса, и атрибут, представляющий суперкласс, должен быть там, когда вызывается оператор class
. Лучшее, что вы можете сделать, это использовать нормальный import
, ссылаться на суперкласс через модуль и надеяться, что вы сможете перестроить достаточно остального кода, чтобы он работал.
Если вы все еще застряли в этой точке, другой способ, который может помочь, - использовать функции доступа для оповещения о доступе между одним модулем и другим. Например, если у вас есть класс A
в одном модуле и вы хотите ссылаться на него с другого модуля, но не можете из-за круговой ссылки, вы можете иногда создать третий модуль с функцией в нем, которая просто возвращает ссылку на класс A
. Если вы обобщите это на набор функций доступа, это не будет таким же громким, как кажется.
Если все остальное не удается, вы можете перемещать операции импорта в свои функции и методы - но я обычно оставляю это как последнее средство.
--- EDIT ---
Просто хотел добавить что-то новое, я обнаружил недавно. В выражении «class» суперкласс на самом деле является выражением Python. Таким образом, вы можете сделать что-то вроде этого:
>>> b=lambda :object
>>> class A(b()):
... pass
...
>>> a=A()
>>> a
<__main__.A object at 0x1fbdad0>
>>> a.__class__.__mro__
(<class '__main__.A'>, <type 'object'>)
>>>
Это позволяет определить и импортировать функцию доступа, чтобы получить доступ к классу из другого определения класса.
Возможный дубликат [Циркулярная зависимость импорта в Python] (http://stackoverflow.com/questions/1556387/circular-import-dependency-in-python) –