В Python, как я могу предотвратить включение определения класса несколько раз?

82
11

У меня возникают проблемы с подклассом с несколькими суперклассами, вызывающими методы init своих родителей. Я получаю сообщение об ошибке, когда unbound __init__ нуждается в экземпляре родителя, но получил экземпляр дочернего элемента. Некоторые другие вопросы в StackOverflow указывали, что это из родительского класса, который определяется несколько раз, что я подтвердил простым script, введенным в интерпретатор.


Примечание. Это НЕ код, о котором я задаю вопрос. Это пример, иллюстрирующий проблему переопределения базового класса и вызывание класса Inherited, который больше не функционирует должным образом.


>>> class Base(object):
... def __init__(self):
... print "Base!"
...
>>> class Inherited(Base):
... def __init__(self):
... Base.__init__(self)
... print "Inherited"
...
>>> class Base(object):
... def __init__(self):
... print "Base!"
...
>>> Inherited()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: unbound method __init__() must be called with Base instance as first argument (got Inherited instance instead)
>>>

Мой вопрос: как я могу предотвратить определение базового класса несколько раз? Проект, над которым я работаю, имеет несколько файлов и импорт по всему миру, поэтому было бы сложно реорганизовать все, чтобы просто добавить файл один раз.

спросил(а) 2012-12-17T16:49:00+04:00 7 лет, 10 месяцев назад
1
Решение
81

Такое поведение кажется мне очень подозрительным. Импорт одного и того же модуля по-разному будет по-прежнему иметь ваш класс (Base), ссылающийся на тот же объект класса. Кажется маловероятным, что вы можете попасть в эту ситуацию через импорт.


Однако одним из способов является использование super:

class Base(object):
def __init__(self):
print "Base!"

class Inherited(Base):
def __init__(self):
super(Inherited,self).__init__()
print "Inherited"

class Base(object):
def __init__(self):
print "Base!"

Inherited()


super гарантирует, что вы фактически вызываете базовый класс __init__, а не какой-либо другой класс, который заменил базовый класс в текущем пространстве имен модулей.

ответил(а) 2012-12-17T16:53:00+04:00 7 лет, 10 месяцев назад
81

Проблема, которую вы указали выше, состоит в том, что Inherited подклассы исходного определения Base (первого, которое вы определили), поскольку определения классов обрабатываются по мере их чтения.


Однако во время выполнения используется __init__ второго определения Base. Этот класс ожидает экземпляр самого себя, но вместо этого получает экземпляр первого определения Base.

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


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

ответил(а) 2012-12-17T16:56:00+04:00 7 лет, 10 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема