Python: круговой импорт необходим для проверки типа

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

Ответ более или менее: "Разработайте свою структуру Модуля/Класса правильно, и Вам не будет нужен круговой импорт". Это верно. Я пытался очень трудно сделать надлежащий дизайн для своего текущего проекта, я, по-моему, я был успешен с этим.

Но моя определенная проблема следующая: Мне нужна регистрация типа модуля, который уже импортируется модулем, содержащим класс для проверки по. Но это бросает ошибку импорта.

Как так:

foo.py:

from bar import Bar

class Foo(object):

    def __init__(self):
        self.__bar = Bar(self)

bar.py:

from foo import Foo

class Bar(object):

    def __init__(self, arg_instance_of_foo):
        if not isinstance(arg_instance_of_foo, Foo):
            raise TypeError()

Решение 1: Если я изменил его для проверки типа сравнением строк, это будет работать. Но мне действительно не нравится это решение (представьте comparsion в виде строки, является довольно дорогим для простой проверки типа и мог получить проблему когда дело доходит до рефакторинга).

bar_modified.py:

from foo import Foo

class Bar(object):

    def __init__(self, arg_instance_of_foo):
        if not arg_instance_of_foo.__class__.__name__ == "Foo":
            raise TypeError()

Решение 2: Я мог также упаковать эти два класса в один модуль. Но мой проект имеет много различных классов как пример "Панели", и я хочу разделить их в различные файлы модуля.

После того, как моими собственными 2 решениями не является никакая опция для меня: у Кого-либо есть более хорошее решение для этой проблемы?

8
задан Philip Daubmeier 9 April 2010 в 15:31
поделиться

3 ответа

Лучшее решение - не проверять типы.

Другое решение - не создавать экземпляр и вообще не ссылаться на Foo или Bar, пока оба класса не будут загружены. Если первый модуль загружен первым, не создавайте Bar и не ссылайтесь на Bar до тех пор, пока не будет выполнен оператор class Foo. Аналогично, если второй модуль загружается первым, не создавайте Foo и не ссылайтесь на Foo до тех пор, пока не будет выполнен оператор class Bar.

Это в основном источник ImportError, которого можно было бы избежать, если бы вы сделали "import foo" и "import bar" вместо этого, и использовали foo.Foo там, где вы сейчас используете Foo, и bar.Bar там, где вы сейчас используете Bar. При этом вы больше не ссылаетесь ни на один из них, пока не будет создан Foo или Bar, что, надеюсь, произойдет только после создания обоих (иначе вы получите AttributeError).

5
ответ дан 5 December 2019 в 14:02
поделиться

Вы можете программировать против интерфейс (ABC - абстрактный базовый класс в python), а не конкретный тип Bar . Это классический способ разрешения взаимозависимостей пакета / модуля на многих языках. Концептуально это также должно привести к лучшему проектированию объектной модели.

В вашем случае вы должны определить интерфейс IBar в каком-то другом модуле (или даже в модуле, содержащем класс Foo - в зависимости от использования этого abc ). Ваш код будет выглядеть так:

foo.py:

from bar import Bar, IFoo

class Foo(IFoo):
    def __init__(self):
        self.__bar = Bar(self)

# todo: remove this, just sample code
f = Foo()
b = Bar(f)
print f
print b
x = Bar('do not fail me please') # this fails

bar.py:

from abc import ABCMeta
class IFoo:
    __metaclass__ = ABCMeta

class Bar(object):
    def __init__(self, arg_instance_of_foo):
        if not isinstance(arg_instance_of_foo, IFoo):
            raise TypeError()
5
ответ дан 5 December 2019 в 14:02
поделиться

Вы можете просто отложить импорт в bar.py следующим образом:

class Bar(object):

    def __init__(self, arg_instance_of_foo):
        from foo import Foo
        if not isinstance(arg_instance_of_foo, Foo):
            raise TypeError()
2
ответ дан 5 December 2019 в 14:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: