2010-02-17 3 views
2

Для следующего кода Python:У всех динамических языков есть проблема с циклическим импортом?

first.py

# first.py 
from second import Second 

class First: 
    def __init__(self): 
     print 'Second' 

second.py

# second.py 
from first import First 

class Second: 
    def __init__(self): 
     print 'Second' 

После создания файлов и запуск следующих из оболочки:

python first.py 

Я получаю сообщение об ошибке: ImportError: cannot import name Second

Есть ли другие динамические языки, такие как Ruby, такого рода проблемы? Причина, по которой я спрашиваю, заключается в том, что я сталкиваюсь с этой проблемой в проекте Django, где 2 модели зависят друг от друга. Я знаю, что возможные решения - это перепроектирование проекта или импорт по требованию. Я просто хочу знать, столкнулись ли разработчики других динамических языков с этой проблемой.

+2

Вы всегда должны подклассифицировать «объект», а не ничего, чтобы вы использовали классы нового стиля. –

+1

@ Майк, он не уточнил свою версию Python. –

+4

@Hamish Grubijan, i) Он использовал оператор печати, который ушел на Python 3, ii) Он сказал, что использует Django, который не поддерживает Python 3, и iii) никто не использует Python 3; Python 2 - разумное предположение по умолчанию. –

ответ

11

Python может в некоторой степени обрабатывать круговые импорты. В тех случаях, когда не может быть смысла, решение, вероятно, все еще не имеет смысла на другом языке. Большинство проблем можно устранить, используя import first, а затем ссылаясь на first.First вместо from first import First.

Было бы лучше, если бы вы могли переместить общий код в собственный модуль или каким-то образом реорганизовать необходимость циклического импорта. Циркулярный импорт всегда указывает на проблему с дизайном.

+1

Итак, если я хочу разделить тысячи строк кода на несколько файлов, это проблема дизайна? – asmeurer

+1

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

3

Рекурсивные определения не являются проблемой, ограниченной динамическими языками. Это также часто является проблемой в языках статических типов. Он может отображаться как ошибка компиляции, потому что один из типов будет использоваться до его определения.

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

В Python вы можете решить эту проблему, перемещая импорт с верхнего уровня на те функции, в которых они необходимы. Кроме того, круговая ссылка на самом деле не является ошибкой, поэтому, если вы будете осторожны, вы можете заставить ее работать в любом случае.

0

Это не проблема, связанная с «динамическими» языками. Это архитектурная проблема. Вам нужно лучше взглянуть на то, как вы структурировали вещи.

1

Логически это парадокс. Это проблема с курицей и яйцом в кодовой форме. Один из них должен быть первым. Как было предложено другими, пожалуйста, вернитесь к чертежной доске, и в будущем вам будет лучше. Языки не позволяют вам делать это по какой-то причине!

+1

Это может быть плохая идея, но не парадокс состоит в том, что два модуля зависят друг от друга. – Draemon

+0

Чтобы быть зависимыми друг от друга постепенно, возможно, но отчетливо, как это было предложено в ОП? Парадокс. – jathanism

+0

Нет, это не так. Вы когда-нибудь слышали о рекурсии? – asmeurer

2

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

Однако с моделями специфически Python/Django, вы можете использовать строковые имена установки внешних ключей, чтобы избежать этих проблем циклическую зависимость -

#appA/models.py 
class A(models.Model): 
    b = models.ForeignKey('appB.b') 

#appB/models.py 
class B(models.Model): 
    a = models.ForeignKey('appA.a') 

Круговые ссылки в таблицах БД не обязательно плохо (но не всегда хороши); Django позволяет определять ключи со строкой, чтобы помочь в ситуациях, где это необходимо.Если вам действительно необходимо создать экземпляр двух классов внутри друг друга, у вас возникнут большие проблемы.

1

Обратите внимание: если вы просто переместите свой импорт в конец своего модуля, циклический импорт будет работать, как ожидалось. Как так:

first.py

# first.py 
class First: 
    def __init__(self): 
    print 'Second' 
from second import Second 

second.py

# second.py 
class Second: 
    def __init__(self): 
     print 'Second' 
from first import First 

Fredrik Lundh's import reference стоит прочитать. Тем не менее, как вам посоветовали другие, вам лучше отказаться от кода, чтобы полностью исключить циркулярный импорт.

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