python multiple-inheritance super diamond-problem

herencia mĂșltiple de Python que pasa argumentos a los constructores usando super



python super (2)

Considere el siguiente fragmento de código de Python

class A(object): def __init__(self, a): self.a = a class B(A): def __init__(self, a, b): super(B, self).__init__(a) self.b = b class C(A): def __init__(self, a, c): super(C, self).__init__(a) self.c = c class D(B, C): def __init__(self, a, b, c, d): #super(D,self).__init__(a, b, c) ??? self.d = d

Me pregunto cómo puedo pasar a , c a los constructores de las clases base correspondientes.

Gracias,


Bueno, cuando se trata de herencia múltiple en general, sus clases base (desafortunadamente) deben diseñarse para herencia múltiple . Las clases B y C en su ejemplo no lo son, y por lo tanto, no pudo encontrar una manera adecuada de aplicar super en D

Una de las formas comunes de diseñar sus clases base para herencia múltiple, es que las clases base de nivel medio acepten __init__ adicionales en su método __init__ , que no pretenden usar, y los transmitan a su super llamada.

Aquí hay una forma de hacerlo en python:

class A(object): def __init__(self,a): self.a=a class B(A): def __init__(self,b,**kw): self.b=b super(B,self).__init__(**kw) class C(A): def __init__(self,c,**kw): self.c=c super(C,self).__init__(**kw) class D(B,C): def __init__(self,a,b,c,d): super(D,self).__init__(a=a,b=b,c=c) self.d=d

Esto puede verse como decepcionante, pero así es como es.


Desafortunadamente, no hay manera de hacer que esto funcione con super() sin cambiar las clases de Base. Cualquier llamada a los constructores para B o C intentará llamar a la siguiente clase en el Orden de resolución de métodos , que siempre será B o C lugar de la clase A que asumen los constructores de las clases B y C

La alternativa es llamar a los constructores explícitamente sin el uso de super() en cada clase.

class A(object): def __init__(self, a): object.__init__() self.a = a class B(A): def __init__(self, a, b): A.__init__(self, a) self.b = b class C(object): def __init__(self, a, c): A.__init__(self, a) self.c = c class D(B, C): def __init__(self, a, b, c, d): B.__init__(self, a, b) C.__init__(self, a, c) self.d = d

Todavía hay un inconveniente aquí, ya que el constructor A se llamaría dos veces, lo que realmente no tiene mucho efecto en este ejemplo, pero puede causar problemas en constructores más complejos. Puede incluir una verificación para evitar que el constructor se ejecute más de una vez.

class A(object): def __init__(self, a): if hasattr(self, ''a''): return # Normal constructor.

Algunos llamarían a esto un defecto de super() , y es en cierto sentido, pero también es un defecto en la herencia múltiple en general. Los patrones de herencia de diamante a menudo son propensos a errores. Y muchas de las soluciones para ellos llevan a un código aún más confuso y propenso a errores. A veces, la mejor respuesta es intentar refactorizar su código para usar menos herencia múltiple.