Closed jirarrazaval closed 4 years ago
Hola @jirarrazaval,
Primero que todo, que bueno estés probando tu código mediante pruebas más chicas. También se aprecia el esfuerzo de crearlo y escribirlo para esconder tu solución específica. 😄
Revisé tu repositorio, y encontré donde está tu situación descrita. El problema es que el ejemplo pequeño que nos muestras no sigue exactamente lo que hay en tu código, específicamente, no agregaste unas llamadas a super().m()
que ocurren en las clases intermedias (en este caso, B
, C
y D
). Si las ponemos en tu ejemplo, se vería algo así:
from abc import ABC, abstractmethod
class A(ABC):
@abstractmethod
def m(self):
print("A")
class B(A):
def m(self):
super().m()
print("B")
class C(A):
def m(self):
super().m()
print("C")
class D(A):
def m(self):
super().m()
print("D")
class E(B,C,D):
def m(self):
C.m(self)
E().m()
Si ejecutas eso, te encontrarás con algo que probablemente no esperabas. Imprime:
A
D
C
¿Por qué? ¡Porque super
llama a la clase siguiente en el orden de multiherencia, no la clase madre directa necesariamente! Luego, la situación que tienes es que:
E
ejecuta m()
. Este llama a implementación de C
.m
de C
, este llama a super().m()
, lo cual llama a D
(el siguiente en el orden).m
de D
, este llama a super().m()
, lo cual llama a A
(el siguiente en el orden).m
de A
, que no llama a otra ejecución. Imprime A
, termina ejecución.m
en D
. Imprime D
, termina ejecución.m
en C
. Imprime C
, termina ejecución.m
en E
, termina ejecución.Como es una instancia de E
quien debe ejecutar el super()
, este seguirá el orden de herencia definido, que sería: E --> B --> C --> D --> A
. Luego, si E
llamara a B.m(self)
, obtendríamos:
A
D
C
B
Lo que ocurría no era que siempre se llame a la implementación del de más a la derecha (D
en este caso), si no que se llaman a varias implementaciones, pero esta siempre se llamaba y su contenido se ejecutaba antes que el resto de las otras implementaciones.
Eso, por eso ocurre lo que indicas en tu implementación. Espero se entienda, cualquier cosa comentas aquí 😄 .
Saludos.
Aaaahh buenisimo! Muchas gracias @fdoflorenzano por tu explicación!! Pero cómo se arregla?? Osea como hago para que herede solo lo que pasa en B (incluyendo el super que hay ahi en B)?? Hay alguna forma de hacerlo correcto?? Porque no se como arreglarlo para que no se implemente todo :(
Traté de cambiar los super().m() por A().m() pero me dice que: TypeError: Can't instantiate abstract class A with abstract methods m
Enverdad no sé cual es la forma de hacerloo
Hola @jirarrazabal,
A().m()
te lanza ese error porque A()
crea una nueva instancia de A
, que es abstracta. Lo que necesitas es llamar a un método de otra clase usando como instancia a la actual, no crear una nueva. Nota que en el ejemplo, la implementación de m
en E
hace eso. Llama a m
de C
con la instancia actual de E
:)
¡Avisa si ahora pudiste!
@fdoflorenzano pucha la verdad es que no me funciona y no entiendo lo que me dices que ponga. Porque quiero que corra lo que pasa en C. Hice esto
class E(B,C,D):
def m(self):
C.m(self)
E().m()
Y el output es
A
D
C
Por lo que me dijiste recién entendí que tenía que hacer esto
class E(B,C,D):
def m(self):
A.m(self)
E().m()
Y imprime solo
A
Yo sólo quiero que el output sea:
A
C
Pero enserio no entiendo cómo se hace :( para que sólo corra eso
Hola @jirarrazabal,
Para el primer caso:
class E(B,C,D):
def m(self):
C.m(self)
E().m()
Como m
en E
llama a la implementación de C
, pero la implementación de C
llama a super
, este último redirige a la siguiente clase en el orden de multiherencia (como explicado en en mi primer comentario), entonces llama a D
, el cual luego llama recién a A
.
Para el segundo:
class E(B,C,D):
def m(self):
A.m(self)
E().m()
Ahora m
en E
llama a la implementación de A
directamente, por eso no pasa por una clase intermedia.
Lo que te dije en mi comentario anterior era notar que A().m()
no era lo que buscabas usar, si no A.m(self)
. No dije donde aplicarlo.
No estoy siendo explícito a propósito para que te des cuenta como ordenar las llamadas por tu cuenta :) Todo lo que necesitas ya está dicho, dale una vuelta a como funciona el primer caso que publicaste originalmente, como funciona los últimos que comentaste, y piensa como llegar a lo que necesitas.
Saludos, quedo atento.
Aaaaahh no había entendido la diferencia entre A().m()
y A.m(self)
Ahora me funcionooo alfiiinnnn graciass!! :smile:
Hola, he probado de todas las formas pero no se por qué cuando hago una subclase que hereda de otras 3, en un atributo solo hereda de la ultima clase del parentesis en que defino la clase al principio, aunque especifique en el atriuto que herede especificamente de una clase.
Lo peor es que he hecho ejemplos y si me funcionan, pero en mi codigo no y no sé por qué. Es una lata porque estoy como atrapada y no sé a quien pedirle ayuda porque si me funciona el ejemplo peor en mi codigo solo hereda de la ultima clase :(
es de esta forma (y esta si funciona pero mi codigo no)
Ayuda que hago