python3 – comportamiento de super () en multi-herencia

Sé que la súper () y la herencia múltiple ya se han discutido aquí. Pero no encontré una solución con respecto a mi problema específico en python3. Supongamos que tenemos:

#! /usr/bin/env python3 class A(object): def __init__(self): super().__init__() def foo(self): print("The") class B(object): def __init__(self): super().__init__() def foo(self): print("world") class C(B): def __init__(self): super().__init__() def foo(self): super().foo() print("is") class D(A,C): def __init__(self): super().__init__() def foo(self): super().foo() print("nice") d = D() d.foo() 

Esto me llevará:

 The nice 

Por otro lado, si cambio el orden de herencia en D () a:

 class D(C,A): def __init__(self): super().__init__() def foo(self): super().foo() print("nice") 

Me da

 world is nice 

Yo, sin embargo, solo obtengo la salida deseada:

 The world is nice 

utilizando:

 class D(C,A): def __init__(self): super().__init__() def foo(self): A.foo(self) C.foo(self) print("nice") 

Lo cual encuentro bastante poco elegante.

Así que mi pregunta es: ¿es posible usar super () en python3 invocando el súper método de ambas súper clases en lugar de solo la primera?

Desafortunadamente, sin un conocimiento del orden de resolución de método (MRO) de D , no hay manera de llamar a super() en D para obtener ambas clases base.

Pero el MRO es un concepto poderoso. En el segundo caso,

 class D(C,A): ... 

el (MRO) es

 >>> D.mro() [, , , , ] 

En la medida en que llamar a super() lleva a la siguiente clase en el MRO, como dijo el Sr. Pieters, y desea que las declaraciones impresas aparezcan en el orden de A , B , C y luego D , simplemente coloque super().foo() primero e print(...) segundo en cada definición de foo() . La única excepción es no poner super().foo() en la clase A porque foo() no está definido en el object .

Solución

 #! /usr/bin/env python3 class A(object): def __init__(self): super().__init__() def foo(self): print("The") class B(object): def __init__(self): super().__init__() def foo(self): super().foo() # Inserted print("world") class C(B): def __init__(self): super().__init__() def foo(self): super().foo() print("is") class D(C,A): # Correct ordering def __init__(self): super().__init__() def foo(self): super().foo() print("nice") d = D() d.foo() 

Solución alternativa

El MRO de D(A,C) en el primer caso también incluye todas las clases, por lo que con el orden correcto de las declaraciones super() e print(...) , se puede hacer que funcione:

 class A(object): def foo(self): print("The") super().foo() class B(object): def foo(self): print("world") class C(B): def foo(self): super().foo() print("is") class D(A,C): def foo(self): super().foo() print("nice") D().foo() 

Otras lecturas

Para comprender el orden de herencia (p. Ej., class D(C,A) o class D(A,C) ) y MRO, consulte https://www.python.org/download/releases/2.3/mro/ . El orden de resolución del método C3 se describe en detalle y hay jerarquías de clases ASCII bien dibujadas con la etiqueta MRO.

Tal vez esto ayude

  class A(object): def __init__(self): super().__init__() def foo(self): print("The") if hasattr(super(), 'foo'): super().foo() class B(object): def __init__(self): super().__init__() def foo(self): print("world") class C(B): def __init__(self): super().__init__() def foo(self): super().foo() print("is") class D(A,C): def __init__(self): super().__init__() def foo(self): super().foo() print("nice") d = D() d.foo() 

salida:

 The world is nice