Наследование класса Python: AttributeError: объект '[SubClass]' не имеет атрибута 'xxx'
У меня есть следующий базовый класс и подкласс:
class Event(object):
def __init__(self, sr1=None, foobar=None):
self.sr1 = sr1
self.foobar = foobar
self.state = STATE_NON_EVENT
# Event class wrappers to provide syntatic sugar
class TypeTwoEvent(Event):
def __init__(self, level=None):
self.sr1 = level
self.state = STATE_EVENT_TWO
Далее в моем коде я проверяю экземпляр класса TypeTwoEvent
, проверяю, существует ли поле, которое, как я знаю, существует в базовом классе - я ожидал, что его значение по умолчанию будет равным None
. Тем не менее, мой код вызывает следующее исключение:
AttributeError: у объекта "TypeTwoEvent" нет атрибута "foobar"
У меня сложилось впечатление, что поля базового класса будут унаследованы подклассом и что создание экземпляра подкласса будет создавать экземпляр базового класса (и, таким образом, вызывать его конструктор)...
Что мне здесь не хватает? Почему TypeTwoEvent
не имеет атрибута foobar
- когда базовый класс, из которого он получен, имеет атрибут foobar
?
Ответы
Ответ 1
Ваш подкласс должен быть:
class TypeTwoEvent(Event):
def __init__(self, level=None, *args, **kwargs):
super(TypeTwoEvent, self).__init__(*args, **kwargs)
self.sr1 = level
self.state = STATE_EVENT_TWO
Поскольку вы переопределяете метод __init__
, вам нужно вызвать родительский метод, если вы хотите, чтобы родительское поведение имело место.
Помните, __init__
не является специальным методом, несмотря на его странное имя. Это просто метод, который автоматически вызывается после создания объекта. В противном случае это обычный метод, и применяются обычные правила наследования.
super(ClassName, self).__init__(arguments, that, goes, to, parents)
это синтаксис для вызова родительской версии метода.
Для *args
и **kwargs
он просто гарантирует, что мы перехватим все дополнительные аргументы, переданные в __init__
и передадим его родительскому методу, так как подпись вашего дочернего метода не сделала этого, и родительский нужен для работы этих аргументов.
Ответ 2
Вы переопределяете конструктор (__init__
) родительского класса. Чтобы расширить его, вам нужно явно вызвать конструктор родителя с вызовом super()
.
class TypeTwoEvent(Event):
def __init__(self, level=None, **kwargs):
# the super call to set the attributes in the parent class
super(TypeTwoEvent, self).__init__(**kwargs)
# now, extend other attributes
self.sr1 = level
self.state = STATE_EVENT_TWO
Обратите внимание, что вызов super
не всегда находится в верхней части метода __init__
в вашем подклассе. Его местоположение зависит от вашей ситуации и логики.
Ответ 3
Когда экземпляр создан, вызывается его метод __init__
. В этом случае это TypeTwoEvent.__init__
. Методы суперкласса не будут вызываться автоматически, потому что это будет очень запутанным.
Вы должны вызвать Event.__init__(self, ...)
из TypeTwoEvent.__init__
(или использовать super
, но если вы не знакомы с ним, сначала прочитайте его, чтобы вы знали, что делаете).
Ответ 4
Вам нужно вызвать метод __init__
базового класса из метода __init__
унаследованного класса.
Смотрите здесь, как это сделать.
Ответ 5
У меня также была проблема с этим, но я поместил super().__init__()
в нижней части моего производного класса и почему он не работает. Потому что я пытаюсь использовать атрибуты, которые не инициализированы.