2010-02-17 1 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 стоит прочитать. Тем не менее, как вам посоветовали другие, вам лучше отказаться от кода, чтобы полностью исключить циркулярный импорт.