2011-04-12 23 views
19

Me gustaría dar a una clase hija algunos atributos adicionales sin tener que llamar explícitamente a un nuevo método. Entonces, ¿hay alguna manera de dar a la clase heredada un método de tipo __init__ que no anule el método __init__ de la clase principal?Método python __init__ en la clase heredada

He escrito el código a continuación puramente para ilustrar mi pregunta (de ahí el mal nombre de los atributos, etc.).

class initialclass(): 
    def __init__(self): 
     self.attr1 = 'one' 
     self.attr2 = 'two'  

class inheritedclass(initialclass): 
    def __new__(self): 
     self.attr3 = 'three' 

    def somemethod(self): 
     print 'the method' 


a = inheritedclass() 

for each in a.__dict__: 
    print each 

#I would like the output to be: 
attr1 
attr2 
attr3 

Gracias

+0

llamada 'initialclass .__ init__' en el constructor de la clase derivada. Sin embargo, el orden de 'attrX' no está garantizado. – khachik

+0

* No * anule '__new__' a menos que sepa exactamente lo que hace y por qué necesita jugar con él. Tu propagablemente no sabes. No es otro nombre para '__init__'. Son tres niveles más mágicos que uno que normalmente nos preocupa, especialmente los principiantes. – delnan

+0

Tenga en cuenta que el argumento para '__new__' es la _clase_ de' self', no 'self', ya que es un método de clase implícito. Entonces, en tu ejemplo, en realidad estás configurando el atributo de clase 'inheritedclass.attr3', no' self.attr3' como creías. –

Respuesta

32

Por lo que yo sé que no es posible, sin embargo, puede llamar al método init de la superclase, como esto:

class inheritedclass(initialclass): 
    def __init__(self): 
     initialclass.__init__(self) 
     self.attr3 = 'three' 
+2

brillante, he estado tratando de encontrar una buena manera de manejar este caso por un tiempo – qwwqwwq

16

Sólo tiene que llamar la __init__ de los padres usando super:

class inheritedclass(initialclass): 
    def __new__(self): 
     self.attr3 = 'three' 
     super(initialclass, self).__init__() 

yo recomiendo seguir las convenciones de nombres de Python y empezar una clase con una letra mayúscula, por ejemplo, InheritedClass y InitialClass. Esto ayuda a distinguir rápidamente las clases de los métodos y las variables.

+2

Específicamente, use 'super (DerivingClass, self) .__ init __()'. O simplemente 'super() .__ init __()' en Python 3. Edit: -1 porque 1. 'super' necesita la clase heredada (!) Y 2. anulas' __new__' innecesariamente, y el código a partir de ahora está en hecho incorrecto (crea un atributo ** clase ** 'attr3'). – delnan

+0

esto funciona con el método __new__ pero como lazyr me dijo (correctamente) que no debería usar __new__, creo que la respuesta correcta para mí es yexo. ¡Gracias! – Anake

+0

@Anake Credit donde se debe crédito, fue @delnan quien le dijo que no use '__new__', solo le expliqué lo que su código realmente hizo. Por cierto, '__new__' ** debe ** devolver una instancia de su clase si lo implementa. En la respuesta anterior, y en su código también, 'inheritedclass() es None'! En otras palabras, no funciona en absoluto. (Erróneamente le di una respuesta a esta respuesta, no leí el código correctamente, y ahora no puedo cambiarlo :(.) –

0

Sólo tiene que llamar un método designado desde init de los padres, si es que existe:

class initialclass(): 
    def __init__(self): 
     self.attr1 = 'one' 
     self.attr2 = 'two' 
     if hasattr(self, 'init_subclass'): 
      self.init_subclass() 

class inheritedclass(initialclass): 
    def init_subclass(self): 
     self.attr3 = 'three' 
+1

Virtual - 1. No es necesario hacer ningún trabajo adicional, y mucho menos 'hasattr' y métodos adicionales, en la clase principal. Simplemente puede definir un nuevo' __init__' que llame al 's de padre'' usando' super'. – delnan

+0

@delnan Lo sé esto, pero la pregunta era "¿hay alguna manera de dar a la clase heredada un método de tipo init _que no anule el método init de la clase principal?". Lo he proporcionado de esta manera. Esto tiene el beneficio adicional de dar un punto de entrada llamar a _only_ la subclase init desde algún otro método de subclase. –

+1

Es por eso que es virtual. Sé que es lo que OP solicitó, pero OP preguntó "¿Cómo uso un martillo para hacer esto?" y la respuesta es "Usas un destornillador" ". – delnan

3

Es increíblemente simple. Defina un nuevo método __init__ y llame al padre __init__ al principio.

# assuming a class Base, its __init__ takes one parameter x 

class Derived(Base): 
    def __init__(self, x, y): 
     # whatever initialization is needed so we can say Derived is-a Base 
     super(Derived, self).__init__(x) 
     # now, add whatever makes Derived special - do your own initialization 
     self.y = y 

En Python 3, que no tiene que (y por lo tanto además probablemente no debería, por simplicidad) heredar explícitamente de object o pasar la clase y self a super.

5

En primer lugar estás mezclando __init__ y __new__, son different things. __new__ no toma instancia (self) como argumento, toma clase (cls). En cuanto a la parte principal de su pregunta, lo que tiene que hacer es usar super para invocar la superclase '__init__.

El código debería tener este aspecto:

class initialclass(object): 
    def __init__(self): 
     self.attr1 = 'one' 
     self.attr2 = 'two'  

class inheritedclass(initialclass): 
    def __init__(self): 
     self.attr3 = 'three' 
     super(inheritedclass, self).__init__() 
+0

gracias, mi error sobre el nuevo método. Estoy tratando de usar super y sigo recibiendo este error: TypeError: super() argumento 1 debe ser type, no classobj. (Copié y pegué tu código exactamente igual) – Anake

+1

@Anake: 'initialclass' necesita heredar' object' ('clase initialclass (object)'), de lo contrario es una clase de estilo antiguo, que es poco más que un dolor de cabeza- inducir reliquias del pasado y debe evitarse. – delnan

+0

aaah, ok gracias. (también gracias vartec por actualizar). – Anake

Cuestiones relacionadas