2012-04-05 6 views
6

En primer lugar, tengo que disculparme por no tener un título mejor. Siéntase libre de cambiarlo si encuentra uno más apropiado.herencia pitón diamante y el uso de super() en los padres de la clase derivada

Básicamente, he sido intervenidos por el comportamiento de la herencia múltiple de Python. En mi previous SO question, me ordenaron leer Python's C3 MRO. Eso realmente me ayuda a tener una mejor comprensión de la herencia múltiple en Python. Justo cuando creía entenderlo, me topé con la siguiente situación, que parece que no tiene sentido.

class UltimateBase(object): 
    def check(self): 
     print 'base check' 

class AMixin1(UltimateBase): 
    def check(self): 
     print 'check A' 

class BMixin1(UltimateBase): 
    def check(self): 
     print 'check B' 

class CMixin1(UltimateBase): 
    def check(self): 
     print 'check C' 

class AMixin2(UltimateBase): 
    def check(self): 
     print 'check A' 
     return super(AMixin2, self).check() 

class BMixin2(UltimateBase): 
    def check(self): 
     print 'check B' 
     return super(BMixin2, self).check() 

class CMixin2(UltimateBase): 
    def check(self): 
     print 'check C' 
     return super(CMixin2, self).check() 

class MyView1(AMixin1, BMixin1, CMixin1): 
    pass 

class MyView2(AMixin2, BMixin2, CMixin2): 
    pass 

class MyView3(AMixin1, BMixin2, CMixin2): 
    pass 

class MyView4(AMixin2, BMixin1, CMixin2): 
    pass 

class MyView5(AMixin2, BMixin2, CMixin1): 
    pass 

class MyView6(AMixin1, BMixin1, CMixin2): 
    pass 

class MyView7(AMixin1, BMixin2, CMixin1): 
    pass 

class MyView8(AMixin2, BMixin1, CMixin1): 
    pass 

myview1 = MyView1() 
myview2 = MyView2() 
myview3 = MyView3() 
myview4 = MyView4() 
myview5 = MyView5() 
myview6 = MyView6() 
myview7 = MyView7() 
myview8 = MyView8() 

myview1.check() 
print '------------------------' 
myview2.check() 
print '------------------------' 
myview3.check() 
print '------------------------' 
myview4.check() 
print '------------------------' 
myview5.check() 
print '------------------------' 
myview6.check() 
print '------------------------' 
myview7.check() 
print '------------------------' 
myview8.check() 
print '------------------------' 

Salidas:

check A 
------------------------ 
check A 
check B 
check C 
base check 
------------------------ 
check A 
------------------------ 
check A 
check B 
------------------------ 
check A 
check B 
check C 
------------------------ 
check A 
------------------------ 
check A 
------------------------ 
check A 
check B 
------------------------ 

puedo trazar un patrón basado en la observación de las salidas, pero me molesta que no entiende la razón de este resultado.

que tienen preguntas como, por ejemplo, ¿por qué myview2.check() retorno

check A 
check B 
check C 
base check 

no

check A 
base check 

Me parece que me falta una pieza clave sobre la herencia múltiple. Por favor llena el espacio para mí.

Respuesta

4

Cuando se llama a myview2.check(), que atraviesa los hermanos luego llama a la clase base. Cada vez que uno de esos recorridos golpea AMixin1, BMixin1 o CMixin1, se detiene, porque esas clases no llaman super(..., self).check().

Como Benn señala, esto se describe en la official Python documentation. Y si lo piensas bien, tiene que funcionar de esta manera. Las subclases asumirán que el método de clase base no se llama antes de que la subclase llame al super(). Si lo es (o, lo que es peor, si depende del orden en que se enumeran sus hermanos), es muy difícil lidiar con las cosas.

+0

Gracias Chris. Esto es bastante contrario a la intuición. Desde el aspecto del resultado, el 'check()' del ancestro común no se llama a menos que todos los padres llamen 'super()'. ¿Hay literatura que hable de esto? – tamakisquare

+1

En lugar de agregar otra respuesta que diga más o menos lo mismo, simplemente vincularé la documentación de 'super()', que está haciendo la magia en este caso: [Official Python Docs] (http: //docs.python. org/library/functions.html? highlight = super # super). La clave es que llamará a los padres _o hermanos_ de 'tipo' para la herencia múltiple cooperativa. – Benn

+0

@Benn - Esa es exactamente la última pieza que necesito para mi problema. Muchas gracias. – tamakisquare

1

Intenté resolver la misma pregunta. me encontré con el siguiente código ayudó a simplificar la cuestión: (. Básicamente, cuando todos los super s se han visto afectados por una clase, esa clase se llama a)

class A: 
    def f(self): 
    print("............A: the common base of B and C") 

class B(A): 
    def f(self): 
    print("........B: the left base of D") 
    super().f() 

class C(A): 
    def f(self): 
    print("........C: the right base of D") 
    super().f() 

class D(B,C): 
    def f(self): 
    print("....D: the top class") 
    super().f() 

d = D() 

d.f() 

Salida:

....D: the top class 
........B: the left base of D 
........C: the right base of D 
............A: the common base of B and C 

Try Online

Cuestiones relacionadas