2009-05-24 7 views
242

Considere esto: una clase base A, clase B heredando de A, clase C heredando de B. ¿Cuál es una forma genérica de llamar a un constructor clase padre en un constructor? Si esto todavía suena demasiado vago, aquí hay un código.Constructores padre de llamada en cadena en python

class A(object): 
    def __init__(self): 
     print "Constructor A was called" 

class B(A): 
    def __init__(self): 
     super(B,self).__init__() 
     print "Constructor B was called" 

class C(B): 
    def __init__(self): 
     super(C,self).__init__() 
     print "Constructor C was called" 

c = C() 

Así es como lo hago ahora. Pero aún parece un poco demasiado genérico: todavía debe pasar un tipo correcto a mano.

Ahora, he intentado usar self.__class__ como primer argumento para super(), pero, obviamente, no funciona, si lo pones en el constructor para C, es suficiente, se llama al constructor de B. Si haces lo mismo en B, "self" aún apunta a una instancia de C, por lo que terminas llamando al constructor de B otra vez (esto termina en una recursión infinita).

No hay necesidad de pensar en la herencia de diamantes por ahora, solo me interesa resolver este problema específico.

+0

"Pero todavía parece un poco demasiado no genérico - que todavía debe pasar un tipo correcto a mano. "?? Estás pasando el nombre de la clase a super(). Nunca necesita saber la superclase ni nada más. ¿Cómo es esto no genérico? ¿Qué problema crea? ¿Puedes dar un ejemplo de dónde se rompe esto? –

+3

No estoy listo para responder esta pregunta si está completo. Pero de todos modos, ¿y si la clase cambia de nombre? ¿Qué pasa si quiero escribir una función de decorador para automatizar este tipo de encadenamiento? Ahora veo, que esto no es posible, pero a la hora de hacer la pregunta no sabía eso. – shylent

Respuesta

151

De hecho, la forma en que lo está haciendo es la recomendada (para Python 2.x).

La cuestión de si la clase se pasa explícitamente a super es una cuestión de estilo en lugar de funcionalidad. Pasar la clase a super se ajusta a la filosofía de Python de "explícito es mejor que implícito".

+3

Me ha resultado realmente difícil decidir qué respuesta aceptar, pero aceptaré esta, simplemente porque es relevante para la versión de Python que estoy usando. – shylent

+9

En Python 2.6 obtengo 'TypeError: super() El argumento 1 debe ser type, no classobj' utilizando este método. ¿Me estoy perdiendo de algo? – Leopd

+12

@Leopd: 'super()' solo funciona con clases de estilo nuevo, es decir, debe heredar de 'object'. –

159

Python 3 incluye un súper mejorada(), que permite el uso de esta manera:

super().__init__(args) 
+0

si tengo más de una clase para padres, ¿cómo lo haré? ¿Super identificar a qué clase de padres invocar? – Kracekumar

+2

@kracekumar Será determinado por la clase 'Orden de resolución de método (MRO), que puede encontrar llamando a 'MyClassName.mro()'. Puedo ser incorrecto, pero creo que el primer padre especificado es aquel cuyo '__init__' se llamará. –

+0

@ironfroggy, ¿te importaría explicar de qué manera esto mejoró la ayuda con la pregunta? Acabo de encontrar este hilo viejo y estoy teniendo las mismas preguntas exactas. ¿Han mejorado las cosas para Python 2.x desde que se hizo esta pregunta por primera vez? –

22

simplemente hay que escribir:

class A(object): 

    def __init__(self): 
     print "Constructor A was called" 

class B(A): 

    def __init__(self): 
     A.__init__(self) 
     # A.__init__(self,<parameters>) if you want to call with parameters 
     print "Constructor B was called" 

class C(B): 

    def __init__(self): 
     # A.__init__(self) # if you want to call most super class... 
     B.__init__(self) 
     print "Constructor C was called" 
Cuestiones relacionadas