Un problema de herencia múltiple.

Chema Cortes py en ch3m4.org
Mar Ene 15 01:31:19 CET 2008


El Monday 14 January 2008 22:05:52 José Miguel Sánchez Alés escribió:

Te respondo a este mensaje ya que se puede concretar mejor la respuesta:

> A ver si podéis echarme una mano para mejorar el código. Resulta que
> tengo el siguiente esquema de clases:
>
> class A(object)                <----- Nivel 1
>     def __init__
>     def cuota
>     def deuda
>
> class B1(A) y class B2(A)      <----- Nivel 2
>     def __init__
>     def Z__
>     def K__
>
> class C(A)                     <----- Nivel 3
>     def __init__
>         Debe invocar el __init__ de B1 ó de B2
>     def cuota
>     def deuda
>     def Z__
>         Debe invocar la Z__ de B1 ó B2
>
> class D1(B1,C) y D2(B2,C)      <----- Nivel 4
>     def __init__
>         Invoca el __init__ de C
>
> La clase C es simplemente un clase auxiliar que usan D1 y D2. El
> problema está en lo siguiente:

Tal como defines la clase C deberías especializarla por cada clase B1 y B2, o 
sea, que tendrían que usar clases C1 y C2, ambas derivadas de C. Pero 
continúa más adelante...

> Si defino los antecesores de D1 (el mismo razonamiento para D2) como
> B1,C resulta que al invocar los métodos deuda y plazo se ejecutan los
> métodos de A y yo quiero que se ejecuten los métodos de C (que serán los
> que invoquen a los de A)
>
> En cambio si defino C,B1, D1 invoca el método __init__ de C (bien), pero
> en dicho método no es posible invocar el método __init__ de B1 (o de B2
> en el caso de D2), porque super(C,self) es A y super(self.__class__,self)
> es el propio C. Lo mismo pasa con Z__.

Ésto no es correcto del todo: la clase D1 invoca todos los inicializadores de 
sus ancestros. Usando super() y las nuevas clases de python se implementa el 
llamado algoritmo MRO con el que se invocas todos los inicializadores de los 
ancestros, con un orden calculado, y sin llamar dos veces el mismo 
inicializador. En tu caso, para D1(C,B1) el algoritmo MRO ordena las clases 
así A > B1 > C . No necesitarías que C llame explícitamente al inicializador 
de B1; deja que la herencia múltiple trabaje por tí. En cuanto a los 
atributos y métodos, se empieza invocando desde el final de la cadena MRO, en 
este caso los de C (que es precisamente lo que buscas). Quita el Z__ y el 
__init__ de C y deja que la herencia múltiple entre en funcionamiento.

Quizás haya algo que se te escapa y que te está confundiendo: en las 
inicializaciones que invoca D1 pasa una instancia de d1. Cuando dices que 
super(C,self) es A, éso sería si self fuera siempre una instancia de C. Pero 
ocurre que D1 invoca a los inicializadores pasándoles una instancia de D1, y 
resulta que super(C,d1) es B1, no A. Ésa es la "magia" por la que funciona el 
algoritmo MRO.

Creo que ésto responde a tu pregunta, pero reconozco que no he profundizado en 
la jerarquía de clases que has montado y me haya dejado algo.
_______________________________________________
Lista de correo Python-es 
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes





Más información sobre la lista de distribución Python-es