Как избежать кругового импорта в Python? [дубликат]



этот вопрос уже есть ответ здесь:



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



может ли кто-нибудь сказать мне, как избежать кругового импорта в этой ситуации?: У меня есть два класса, и я хочу, чтобы каждый класс имел конструктор (метод), который берет экземпляр другого класса и возвращает экземпляр класса.



более конкретно, один класс является изменяемым, а другой-неизменяемым. Необходим неизменяемый класс
для хэширования, сравнения и так далее. Изменяемый класс необходим для выполнения определенных действий тоже. Это похоже на наборы и замороженные наборы или списки и кортежи.



Я мог бы поместить оба определения классов в один и тот же модуль. Есть ли другие предложения?



пример игрушка будет класс, который имеет атрибут, который представляет собой перечень и класс B, который имеет атрибут, который является кортежем. Затем класс A имеет метод, который принимает экземпляр класса B и возвращает экземпляр класса A (путем преобразования кортежа в список) и аналогично класс B имеет метод, который принимает экземпляр класса A и возвращает экземпляр класса B (путем преобразования списка в кортеж).

726   3  

3 ответов:

только импортировать модуль, не импортировать из модуля:

считают a.py:

import b

class A:
    def bar(self):
        return b.B()

и b.py:

import a

class B:
    def bar(self):
        return a.A()

это работает прекрасно.

рассмотрим следующий пример пакета python, где a.py и b.py зависят друг от друга:

/package
    __init__.py
    a.py
    b.py

есть несколько способов импортировать модуль в python

import package.a           # Absolute import
import package.a as a_mod  # Absolute import bound to different name
from package import a      # Alternate absolute import
import a                   # Implicit relative import (deprecated, py2 only)
from . import a            # Explicit relative import

к сожалению, только 1-й и 4-й варианты на самом деле работают, когда у вас есть циклические зависимости (остальные все поднимают ImportError или AttributeError). В общем, вы не должны использовать 4-й синтаксис, так как он работает только в python2 и рискует столкнуться с другой третьей стороной модули. Так что действительно, только первый синтаксис гарантированно работает. Однако у вас все еще есть несколько вариантов при работе с циклическими зависимостями.

"правка":ImportError и AttributeError проблемы возникают только в python 2. В python 3 импортная техника была переписана и все эти операторы импорта (за исключением 4) будет работать, даже с циклическая зависимость.

Использовать Абсолютный Импорт

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

на a.py

import package.b

на b.py

import package.a

отложить импорт до более позднего времени

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

на a.py

def func():
    from package import b

на b.py

def func():
    from package import a

поместите весь импорт в центральный модуль

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

на __init__.py

from . import a
from . import b

на a.py

import package

def func():
    package.b.some_object()

на b.py

import package

def func():
    package.a.some_object()

так что это ваши варианты (и они все вроде сосать ИМО). Честно говоря, это кажется вопиющей ошибкой в импортном оборудовании python, но это только мое мнение.

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

  • преимущество: более короткие строки доступа по сравнению с чистым абсолютным импортом
  • недостаток: немного больше накладных расходов из-за дополнительного вызова функции

main/sub/a.py

import main.sub.b
b_mod = lambda: main.sub.b

class A():
    def __init__(self):
        print('in class "A":', b_mod().B.__name__)

main/sub/b.py

import main.sub.a
a_mod = lambda: main.sub.a

class B():
    def __init__(self):
        print('in class "B":', a_mod().A.__name__)

Comments

    Ничего не найдено.