genericas - Herencia de la clase Python: AttributeError: el objeto ''[SubClass]'' no tiene ningún atributo ''xxx''
vistas basadas en clases django (5)
Tengo la siguiente clase base y subclase:
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
Más adelante en mi código, estoy inspeccionando una instancia de una clase TypeTwoEvent, verificando si hay un campo que sé que existe en la clase base; esperaba que su valor predeterminado fuera el valor Ninguno. Sin embargo, mi código plantea la siguiente excepción:
AttributeError: el objeto ''TypeTwoEvent'' no tiene atributo ''foobar''
Tenía la impresión de que los campos de clase base serían heredados por la subclase y que crear una instancia de una subclase instanciará la clase base (y por lo tanto invocará a su constructor) ...
¿Que me estoy perdiendo aqui?. ¿Por qué TypeTwoEvent
no tiene un atributo foobar
, cuando la clase base de la que se deriva tiene un atributo foobar
?
Cuando se crea la instancia, se llama a su método __init__
. En este caso, eso es TypeTwoEvent.__init__
. Los métodos de superclase no serán llamados automáticamente porque eso sería muy confuso.
Debería llamar al Event.__init__(self, ...)
desde TypeTwoEvent.__init__
(o use super
, pero si no está familiarizado con él, lea primero para saber qué está haciendo).
Estás anulando el constructor ( __init__
) de la clase padre. Para ampliarlo, debe llamar explícitamente al constructor del padre con una llamada 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
Tenga en cuenta que la super
llamada no siempre está en la parte superior del método __init__
en su subclase. Su ubicación depende de su situación y lógica.
También he tenido problemas con esto, pero puse super().__init__()
en la parte inferior de mi clase derivada y es por eso que no funciona. Porque trato de usar atributos que no están inicializados.
Tu subclase debe ser:
class TypeTwoEvent(Event):
def __init__(self, level=None, *args, **kwargs):
super(TypeTwoEvent, self).__init__(*args, **kwargs)
self.sr1 = level
self.state = STATE_EVENT_TWO
Como anula el método __init__
, debe llamar al método principal si desea que se produzca el comportamiento principal.
Recuerde, __init__
no es un método especial, a pesar de su nombre extraño. Es solo el método al que se llama automáticamente después de crear el objeto. De lo contrario, es un método ordinario, y se aplican las reglas de herencia ordinarias.
super(ClassName, self).__init__(arguments, that, goes, to, parents)
Es la sintaxis para llamar a la versión padre del método.
Para *args
y **kwargs
, solo garantiza que **kwargs
todos los argumentos adicionales pasados a __init__
y los __init__
al método primario, ya que la firma del método secundario no lo hizo y el padre necesita estos argumentos para funcionar.