2011-12-20 3 views
3

У меня в основном следующие настройки в моем пакете:зависимости круговой импорт в пакете с наследств

thing.py:

from otherthing import * 

class Thing(Base): 
    def action(self): 
     ...do something with Otherthing()... 

subthing.py:

from thing import * 

class Subthing(Thing): 
    pass 

otherthing.py :

from subthing import * 

class Otherthing(Base): 
    def action(self): 
     ... do something with Subthing()... 

Если я поместил все объекты в один файл, он будет работать, но этот файл просто станет слишком большим, и его будет сложнее поддерживать. Как решить эту проблему?

+0

Возможный дубликат [Циркулярная зависимость импорта в Python] (http://stackoverflow.com/questions/1556387/circular-import-dependency-in-python) –

ответ

7

Это шагает в опасный аргумент импорта кругов Питона, но, ИМХО, вы можете иметь отличный дизайн и по-прежнему нуждаться в круглых ссылках.

Итак, попробуйте этот подход:

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'>) 
>>> 

Это позволяет определить и импортировать функцию доступа, чтобы получить доступ к классу из другого определения класса.

+0

понял это прямо перед тем, как вы написали этот ответ. спасибо за подробное объяснение! надеюсь, это поможет другим, так как я не мог найти подробного объяснения в Интернете. –

+0

Добро пожаловать. Да, там не так много информации по этой теме. –

-5

Прекратить писать циркулярный импорт. Это просто. thing не может зависеть от все что находится в otherthing.

1) ищите другие вопросы точно так же, как и ваши.

2) прочитайте эти ответы.

3) перепишем otherthing так, что thing зависит от части otherthing, не все otherthing.

+0

Говорить кому-то просто не значит, что проблема не является ответом. Давид Хесс имеет правильный ответ. –

Смежные вопросы