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