- Как избежать циклического импорта в Python?
- ОТВЕТЫ
- Ответ 1
- Ответ 2
- Типы проблем кругового импорта
- 1. Ошибки при импорте модулей с циклическим импортом
- Абсолютный импорт
- Отложить импорт на потом
- Поместите весь импорт в центральный модуль
- 2. Ошибки при использовании импортированных объектов с круговыми зависимостями
- Ответ 3
- Круговой импорт Python
- Что такое циклическая зависимость?
- Проблемы с циклическими зависимостями
- Что такое круговой импорт?
- Как исправить циклические зависимости
- Сворачивание
- Как избежать кругового импорта в Python?
- 3 ответа
- Типы круговых задач import
- 1. Ошибки импорта модулей с циклическим импортом
- Абсолютный Import
- Отложить import на более поздний срок
- Поместите весь импорт в центральный модуль
- 2. Ошибки при использовании импортированных объектов с циклическими зависимостями
Как избежать циклического импорта в Python?
Я знаю, что проблема циклического импорта в python возникла много раз раньше, и я прочитал эти обсуждения. Комментарий, который неоднократно повторяется в этих обсуждениях, заключается в том, что циклический импорт является признаком плохой конструкции, и код должен быть реорганизован, чтобы избежать циклического импорта.
Может ли кто-нибудь сказать мне, как избежать циклического импорта в этой ситуации?: У меня есть два класса, и я хочу, чтобы каждый класс имел конструктор (метод), который принимает экземпляр другого класса и возвращает экземпляр класса.
Более конкретно, один класс является изменяемым, а один неизменным. Требуется неизменный класс для хэширования, сравнения и т.д. Переменный класс необходим, чтобы что-то делать. Это похоже на наборы и фризонсет, или на списки и кортежи.
Я мог бы поместить оба определения классов в один и тот же модуль. Есть ли другие предложения?
Примером игрушки может быть класс A, который имеет атрибут, который является списком и классом B, который имеет атрибут, который является кортежем. Затем класс A имеет метод, который принимает экземпляр класса B и возвращает экземпляр класса A (путем преобразования кортежа в список), и аналогично класс B имеет метод, который принимает экземпляр класса A и возвращает экземпляр класса B (путем преобразования списка в кортеж).
ОТВЕТЫ
Ответ 1
Только импортируйте модуль, не импортируйте его из модуля:
Это прекрасно работает.
Ответ 2
Рассмотрим следующий пример пакета Python, в котором a.py и b.py зависят друг от друга:
Типы проблем кругового импорта
Круговые зависимости импорта обычно делятся на две категории в зависимости о том, что вы пытаетесь импортировать и где вы используете его внутри каждого модуль. (И используете ли вы Python 2 или 3).
1. Ошибки при импорте модулей с циклическим импортом
В некоторых случаях просто импортируйте модуль с циклической зависимостью импорта может привести к ошибкам, даже если вы ничего не ссылаетесь на импортированный модуль.
Есть несколько стандартных способов импортировать модуль в Python
К сожалению, только 1-й и 4-й варианты действительно работают, когда вы имеют круговые зависимости (остальные все поднимают ImportError или AttributeError ). В общем, вы не должны использовать 4-й синтаксис, так как он работает только в Python2 и рискует конфликт с другими сторонними модулями. Так реально только первый синтаксис гарантированно работает.
ОБНОВЛЕНИЕ: проблемы ImportError и AttributeError возникают только в Python 2. В Python 3 была переписана импортная техника и все из этих операторов импорта (за исключением 4) будет работать, даже с круговые зависимости. Решения в этом разделе предназначены для людей, использующих Python 2.
Абсолютный импорт
Просто используйте первый синтаксис импорта выше. Недостатком этого метода является что имена импорта могут быть очень длинными для больших пакетов.
Отложить импорт на потом
Я видел этот метод, используемый во многих пакетах, но он все еще чувствует мне повезло, и мне не нравится, что я не могу посмотреть на верхнюю часть модуля и увидеть все его зависимости, я должен искать все функции также.
Поместите весь импорт в центральный модуль
Это также работает, но имеет ту же проблему, что и первый метод, где все пакетные и субмодульные звонки становятся очень длинными. У этого также есть два основные недостатки — это заставляет импортировать все подмодули, даже если вы используете только один или два, и вы все еще не можете смотреть на любой из субмодули и быстро увидеть их зависимости в верхней части, вы должны просеять функции.
2. Ошибки при использовании импортированных объектов с круговыми зависимостями
Теперь, хотя вы можете импортировать модуль с циклическим импортом зависимость, вы не сможете импортировать объекты, определенные в модуле или на самом деле сможет ссылаться на этот импортированный модуль в любом месте в верхнем уровне модуля, куда вы его импортируете. Ты можешь, однако используйте импортированный модуль внутри функций и блоков кода, которые не запустить при импорте.
Например, это будет работать:
Но это не сработает
Вы получите исключение
AttributeError: модуль ‘package’ не имеет атрибута ‘a’
Как правило, в большинстве действительных случаев циклических зависимостей возможно реорганизовать или реорганизовать код для предотвращения этих ошибок и перемещения ссылки на модули внутри блока кода.
Ответ 3
Мы выполняем комбинацию абсолютного импорта и функций для лучшего чтения и более коротких строк доступа.
- Преимущество: более короткие строки доступа по сравнению с абсолютным абсолютным импортом.
- Недостаток: немного больше накладных расходов из-за дополнительного вызова функции
Источник
Круговой импорт Python
Автор: Scott Robinson
Дата записи
Что такое циклическая зависимость?
Циклическая зависимость возникает, когда два или более модуля зависят друг от друга. Это связано с тем, что каждый модуль определяется в терминах другого (см. рис. 1).
Приведенный выше код изображает довольно очевидную циклическую зависимость. functionA() вызывает functionB() , таким образом, в зависимости от него, и functionB() вызывает functionA() . Этот тип циклической зависимости имеет некоторые очевидные проблемы, которые мы опишем немного дальше в следующем разделе.
Проблемы с циклическими зависимостями
Циклические зависимости могут вызвать довольно много проблем в вашем коде. Например, это может привести к возникновению тесной связи между модулями и, как следствие, к снижению возможности повторного использования кода. Этот факт также делает код более трудным для поддержания в долгосрочной перспективе.
Кроме того, циклические зависимости могут быть источником потенциальных сбоев, таких как бесконечные рекурсии, утечки памяти и каскадные эффекты. Если вы не будете осторожны и у вас есть циклическая зависимость в вашем коде, может быть очень трудно отладить многие потенциальные проблемы, которые она вызывает.
Что такое круговой импорт?
Циклический импорт-это форма циклической зависимости, которая создается с помощью оператора import в Python.
Например, давайте проанализируем следующий код:
Когда Python импортирует модуль, он проверяет реестр модулей, чтобы увидеть, был ли модуль уже импортирован. Если модуль уже зарегистрирован, Python использует этот существующий объект из кэша. Реестр модулей – это таблица модулей, которые были инициализированы и проиндексированы по имени модуля. Доступ к этой таблице можно получить через sys.modules .
Если он не был зарегистрирован, Python находит модуль, инициализирует его при необходимости и выполняет в пространстве имен нового модуля.
В нашем примере, когда Python достигает import module2 , он загружает и выполняет его. Однако модуль 2 также вызывает модуль 1, который, в свою очередь, определяет function1() .
Проблема возникает, когда функция 2() пытается вызвать модуль 1 функция 3() . Поскольку модуль 1 был загружен первым и, в свою очередь , loadedmodule 2 до того, как он смог достичь функции 3 () , эта функция еще не определена и выдает ошибку при вызове:
Как исправить циклические зависимости
В общем, круговой импорт-это результат плохих замыслов. Более глубокий анализ программы мог бы привести к выводу, что зависимость на самом деле не требуется, или что зависимая функциональность может быть перемещена в другие модули, которые не содержат циклической ссылки.
Простое решение заключается в том, что иногда оба модуля могут быть просто объединены в один, более крупный модуль. Полученный код из нашего примера выше будет выглядеть примерно так:
Однако объединенный модуль может иметь некоторые несвязанные функции (тесная связь) и может стать очень большим, если в двух модулях уже есть много кода.
Поэтому, если это не сработает, другим решением могло бы быть отложить импорт модуля 2, чтобы импортировать его только тогда, когда это необходимо. Это можно сделать, поместив импорт модуля 2 в определение функции 1() :
В этом случае Python сможет загрузить все функции в модуле 1, а затем загрузить модуль 2 только при необходимости.
Этот подход не противоречит синтаксису Python, как говорится в документации Python : “Обычно, но не обязательно размещать все операторы импорта в начале модуля (или скрипта, если уж на то пошло)”.
В документации Python также говорится , что рекомендуется использовать import X вместо других операторов, таких как from module import * или from module import a , b,c .
Вы также можете увидеть много кодовых баз, использующих отложенный импорт, даже если нет циклической зависимости, которая ускоряет время запуска, так что это вообще не считается плохой практикой (хотя это может быть плохой дизайн, в зависимости от вашего проекта).
Сворачивание
Циклический импорт-это особый случай циклических ссылок. Как правило, они могут быть решены с помощью лучшего дизайна кода. Однако иногда результирующая конструкция может содержать большое количество кода или смешивать несвязанные функциональные возможности (тесная связь).
Вы сталкивались с циклическим импортом в своем собственном коде? Если да, то как вы это исправили? Дайте нам знать в комментариях!
Источник
Как избежать кругового импорта в Python?
Я знаю, что вопрос о круговом импорте в python поднимался уже много раз, и я читал эти дискуссии. В этих дискуссиях неоднократно делается замечание о том, что циркуляр import является признаком плохой конструкции, и код должен быть реорганизован, чтобы избежать циркуляра import.
Может ли кто-нибудь сказать мне, как избежать кругового import в этой ситуации?: У меня есть два класса, и я хочу, чтобы каждый класс имел конструктор (метод), который берет экземпляр другого класса и возвращает экземпляр класса.
Более конкретно, один класс является изменяемым, а другой-неизменяемым. Неизменяемый класс необходим для хеширования, сравнения и так далее. Изменяемый класс также необходим для выполнения определенных действий. Это похоже на наборы и замороженные наборы или на списки и кортежи.
Я мог бы поместить оба определения классов в один и тот же модуль. Есть ли другие предложения?
Игрушечным примером может быть класс А, который имеет атрибут, представляющий собой список, и класс В, который имеет атрибут, представляющий собой кортеж. Затем класс А имеет метод, который берет экземпляр класса В и возвращает экземпляр класса А (путем преобразования кортежа в список), и аналогично класс В имеет метод, который берет экземпляр класса А и возвращает экземпляр класса В (путем преобразования списка в кортеж).
3 ответа
Недавно я столкнулся с небольшим количеством кода, использующего стилус, и, похоже, не могу понять, как избежать компиляции файлов импорта. В SCSS году я обычно структурировал бы такие вещи следующим образом: scss/ _reset.scss main.scss another.scss И после компиляции у меня остается иерархия CSS.
Я новичок в Python, и раньше я использовал такие языки, как Swift, где импорт не имеет большого значения: вы просто определяете новый класс и можете получить доступ к нему из другой части вашей программы. Я не могу использовать этот способ с Python, потому что здесь импорт работает по-другому: вы.
Рассмотрим следующий пример пакета python, где a.py и b.py зависят друг от друга:
Типы круговых задач import
Циклические зависимости import обычно делятся на две категории в зависимости от того, что вы пытаетесь import и где вы используете его внутри каждого модуля. (И независимо от того, используете ли вы python 2 или 3).
1. Ошибки импорта модулей с циклическим импортом
В некоторых случаях простой импорт модуля с циклической зависимостью import может привести к ошибкам, даже если вы не ссылаетесь ни на что из импортированный модуль.
Существует несколько стандартных способов import модуля в python
К сожалению, только 1-й и 4-й варианты действительно работают, когда у вас есть циклические зависимости (rest все поднимают ImportError или AttributeError ). В целом, вы не должны использовать 4-й синтаксис, так как он работает только в python2 и рискует столкнуться с другими сторонними модулями. Так что на самом деле гарантированно работает только первый синтаксис.
EDIT: Проблемы ImportError и AttributeError возникают только в python 2. В python 3 механизм import был переписан, и все эти операторы import (за исключением 4) будут работать даже с циклическими зависимостями. Хотя решения в этом разделе могут помочь в рефакторинге кода python 3, они в основном предназначены для людей, использующих python 2.
Абсолютный Import
Просто используйте первый синтаксис import выше. Недостатком этого метода является то, что имена import могут быть очень длинными для больших пакетов.
Отложить import на более поздний срок
Я видел, как этот метод использовался во многих пакетах, но он все еще кажется мне хакерским, и мне не нравится, что я не могу посмотреть на верхнюю часть модуля и увидеть все его зависимости, мне также приходится искать все функции.
Поместите весь импорт в центральный модуль
Это также работает, но имеет ту же проблему, что и первый метод, где все вызовы пакетов и подмодулей становятся очень длинными . У него также есть два основных недостатка-он заставляет импортировать все подмодули , даже если вы используете только один или два, и вы все еще не можете посмотреть ни на один из подмодулей и быстро увидеть их зависимости вверху, вам нужно пройти через функции.
2. Ошибки при использовании импортированных объектов с циклическими зависимостями
Теперь, хотя вы можете иметь возможность import модуля с циклической зависимостью import, вы не сможете import каких-либо объектов, определенных в модуле , или фактически сможете ссылаться на этот импортированный модуль в любом месте на верхнем уровне модуля, в который вы его импортируете. Однако вы можете использовать импортированный модуль внутри функций и блоков кода, которые не запускаются на import.
Например, это будет работать:
Но это не сработает
Вы получите исключение
AttributeError: модуль ‘package’ не имеет атрибута ‘a’
Как правило, в большинстве допустимых случаев циклических зависимостей можно провести рефакторинг или реорганизовать код, чтобы предотвратить эти ошибки и переместить ссылки на модули внутри блока кода.
У меня проблема с круговым импортом. У меня есть три тестовых модуля Python: robot_test.py, который является моим основным сценарием, а затем два вспомогательных модуля, controller_test.py и servo_test.py. Идея заключается в том, что я хочу, чтобы controller_test.py определил класс для моего.
У меня есть приложение Django, и где-то в нем есть рекурсивный import, который вызывает проблемы. Из-за размера приложения у меня возникли проблемы с определением причины кругового import. Я знаю, что ответ just don’t write circular imports, но проблема в том, что мне трудно понять, откуда берется.
Источник