2012-04-22 8 views
14

Tengo la siguiente clase base y la subclase:Python herencia de clases: AttributeError: '[subclase]' objeto no tiene atributo 'xxx'

class Event(object): 
    def __init__(self, sr1=None, nr1=None, foo=None, foobar=None, nr2=None, sr2=None, flag = False): 
     self.sr1 = sr1 
     self.nr1 = nr1 
     self.foo = foo 
     self.foobar = foobar 
     self.nr2 = nr2 
     self.sr2 = sr2 
     self.flag = flag 
     self.state = STATE_NON_EVENT 

    def state_name(self): 
     return STATE_NAMES[self.state] 

    def __repr__(self): 
     return '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 

    def __repr__(self): 
     return "Type Two event (Level @: {0:.2f})".format(self.sr1) 

Más adelante en mi código, estoy inspeccionando una instancia de una Clase TypeTwoEvent, buscando un campo que sé que existe en la clase base; esperaba que fuera predeterminado para valorar None. Sin embargo, mi código plantea la siguiente excepción:

AttributeError: 'TypeTwoEvent' object has no attribute 'foobar'

que estaba bajo la impresión de que los campos de la clase de base serían heredados por la subclase y que la creación de una instancia de una subclase será una instancia de la clase base (y por lo tanto invocar su constructor) ...

¿Qué me falta aquí ?. ¿Por qué TypeTwoEvent no tiene un atributo foobar, cuando la clase base de la que se deriva tiene un atributo foobar?

+1

Como se indica a continuación, debe indicar explícitamente que también desea inicializar las superclases. Pero __tomar cuidado__: si tienes herencia múltiple, hacer que esto ocurra se vuelve muy delicado. – katrielalex

Respuesta

15

Su 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 

    def __repr__(self): 
     return "Type Two event (Level @: {0:.2f})".format(self.sr1) 

Debido a que reemplaza el método __init__, por lo que necesita para llamar al método padre si desea que el comportamiento de los padres a suceder.

Recuerde, __init__ no es un método especial a pesar de su extraño nombre. Es solo el método que se llama automáticamente después de que se crea 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 principal del método.

Para *args y **kwargs, sólo se asegura cogemos todos los argumentos adicionales pasados ​​a __init__ y pasarlo al método de los padres, ya que la firma método niño no lo hizo y el padre necesita estos argumentos para trabajar.

+0

Gracias por la edición Chris. Soy francés, y hago esta confusión entre "es" y "es" con bastante frecuencia. No es que mezcle los significados, pero aprendí el idioma hablando, por lo que es (:-)) fácil cambiar un sonido por otro en mi cabeza. –

1

Debe llamar al método __init__ de la clase base del método __init__ de la clase heredada.

Consulte here para saber cómo hacer esto.

2

Cuando se crea la instancia, se llama al 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 inmensamente confuso.

Debe llamar al Event.__init__(self, ...) desde TypeTwoEvent.__init__ (o use super, pero si no está familiarizado con él, léalo primero para saber lo que está haciendo).

2

Está anulando el constructor (__init__) de la clase principal. Para extenderlo, necesita 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 llamada es super no siempre en la parte superior del método __init__ en su sub-clase. Su ubicación depende de su situación y lógica.

0

Tuve un problema con esto también, pero he puesto 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.

Cuestiones relacionadas