súper confuso Python herencia múltiple super ()

Estaba jugando con la herencia múltiple en Python y me encuentro con una situación que no puedo entender cómo sucedió.

Aquí está el diseño de la herencia:

AF / \ | BC | \ | / \ | / D 

El diamante ABCD que todo el mundo conoce. Además de una clase extra “F”, la tiro por diversión.

Aquí está el código:

 class A(object): def foo(self, call_from): print "foo from A, call from %s" % call_from super(A, self).foo("A") class B(A): def foo(self, call_from): print "foo from B, call from %s" % call_from super(B, self).foo("B") class C(A): def foo(self, call_from): print "foo from C, call from %s" % call_from super(C, self).foo("C") class F(object): def foo(self, call_from): print "foo from F, call from %s" % call_from class D(B, C, F): def foo(self): print "foo from D" super(D, self).foo("D") 

salida:

 >>> d = D() >>> d.foo() foo from D foo from B, call from D foo from C, call from B foo from A, call from C foo from F, call from A 

El orden de resolución del método:

 >>> D.__mro__ (, , , , , ) 
  • foo from C, call from B lugar de foo from C, call from D
  • foo from F, call from A simplemente me tira …

Parece que los super() están encadenados de acuerdo con el orden de resolución del método e ignoran la relación entre clases, pero no estoy seguro.

¿Alguien me puede indicar la dirección correcta para entender este comportamiento?

Por favor, tenga en cuenta que estoy tratando de entender el idioma en sí. No tratar de resolver un problema práctico. Así que no tengo un caso de uso para esto. Pero será bueno si alguien puede señalar un caso de uso 🙂


ACTUALIZAR:

Para resumir: super () simplemente le informará qué hay al lado de la base de llamadas en el mro. No es necesario el padre. Mientras que mro construyó una base en la jerarquía de herencia, mro en sí no es la jerarquía de herencia.

El punto principal de super() es seguir el orden de resolución del método. Por eso lo dices tu propia clase, no la clase de tus padres. Es difícil para el progtwigdor predecir qué clase se invocará a continuación, así que deja que super() se encargue de ello.

Ya recibiste la llamada de B desde D, entonces, ¿cómo pudiste llamar a C desde D? D.foo () solo puede llamar a otro foo (), porque solo tiene una función de llamada allí. Va a ser una cadena lineal de llamadas, por lo que las clases deben ser linealizadas, eso es lo que hace el orden de resolución de métodos.

De vez en cuando me resulta útil llamar super en clase padre. Ex.

 class TmpClass0(object): def tmp_method(self): print 'TmpClass0 tmp_method' class TmpClass1(TmpClass0): def tmp_method(self): print 'TmpClass1 tmp_method' 

Ahora quiero usar tmp_method de TmpClass0 desde una instancia de TmpClass2.

 class TmpClass2(TmpClass1): def tmp_method(self): super(TmpClass1, self).tmp_method() 

Resultado:

 In [107]: tmp_class2 = TmpClass2() In [108]: tmp_class2.tmp_method() TmpClass0 tmp_method