La herencia es el mecanismo para lograr la reutilización del código, ya que una clase (clase secundaria) puede derivar las propiedades de otra clase (clase principal). También proporciona transitividad, es decir. si la clase C hereda de P, entonces todas las subclases de C también heredarán de P.
Herencia múltiple
Cuando una clase se deriva de más de una clase base, se denomina herencia múltiple. La clase derivada hereda todas las características del caso base.
Syntax: Class Base1: Body of the class Class Base2: Body of the class Class Derived(Base1, Base2): Body of the class
En la próxima sección, veremos el problema que enfrentamos durante la herencia múltiple y cómo abordarlo con la ayuda de ejemplos.
El problema del diamante
Se refiere a una ambigüedad que surge cuando dos clases Clase2 y Clase3 heredan de una superclase Clase1 y la clase Clase4 hereda tanto de Clase2 como de Clase3. Si hay un método «m» que es un método anulado en uno de Class2 y Class3 o ambos, entonces surge la ambigüedad sobre cuál de los métodos «m» Class4 debería heredar.
Cuando el método se anula en ambas clases
Python3
# Python Program to depict multiple inheritance # when method is overridden in both classes class Class1: def m(self): print("In Class1") class Class2(Class1): def m(self): print("In Class2") class Class3(Class1): def m(self): print("In Class3") class Class4(Class2, Class3): pass obj = Class4() obj.m()
Producción:
In Class2
Nota: cuando llama a obj.m() (m en la instancia de Class4), el resultado es In Class2. Si Class4 se declara como Class4(Class3, Class2), la salida de obj.m() estará en Class3.
Cuando el método se anula en una de las clases
Python3
# Python Program to depict multiple inheritance # when method is overridden in one of the classes class Class1: def m(self): print("In Class1") class Class2(Class1): pass class Class3(Class1): def m(self): print("In Class3") class Class4(Class2, Class3): pass obj = Class4() obj.m()
Producción:
In Class3
Cuando cada clase define el mismo método
Python3
# Python Program to depict multiple inheritance # when every class defines the same method class Class1: def m(self): print("In Class1") class Class2(Class1): def m(self): print("In Class2") class Class3(Class1): def m(self): print("In Class3") class Class4(Class2, Class3): def m(self): print("In Class4") obj = Class4() obj.m() Class2.m(obj) Class3.m(obj) Class1.m(obj)
Producción:
In Class4 In Class2 In Class3 In Class1
La salida del método obj.m() en el código anterior es In Class4 . Se ejecuta el método “m” de Class4. Para ejecutar el método “m” de las otras clases se puede hacer usando los nombres de las clases.
Ahora, para llamar al método m para Class1, Class2, Class3 directamente desde el método «m» de Class4, vea el siguiente ejemplo
Python3
# Python Program to depict multiple inheritance # when we try to call the method m for Class1, # Class2, Class3 from the method m of Class4 class Class1: def m(self): print("In Class1") class Class2(Class1): def m(self): print("In Class2") class Class3(Class1): def m(self): print("In Class3") class Class4(Class2, Class3): def m(self): print("In Class4") Class2.m(self) Class3.m(self) Class1.m(self) obj = Class4() obj.m()
Producción:
In Class4 In Class2 In Class3 In Class1
A continuación se muestra cómo llamar a «m» de Class1 desde «m» de Class2 y «m» de Class3 en lugar de Class4:
Python3
# Python Program to depict multiple inheritance # when we try to call m of Class1 from both m of # Class2 and m of Class3 class Class1: def m(self): print("In Class1") class Class2(Class1): def m(self): print("In Class2") Class1.m(self) class Class3(Class1): def m(self): print("In Class3") Class1.m(self) class Class4(Class2, Class3): def m(self): print("In Class4") Class2.m(self) Class3.m(self) obj = Class4() obj.m()
Producción:
In Class4 In Class2 In Class1 In Class3 In Class1
La salida del código anterior tiene un problema asociado, el método m de Class1 se llama dos veces. Python proporciona una solución al problema anterior con la ayuda de la función super(). Vamos a ver cómo funciona.
La súper función
Python3
# Python program to demonstrate # super() class Class1: def m(self): print("In Class1") class Class2(Class1): def m(self): print("In Class2") super().m() class Class3(Class1): def m(self): print("In Class3") super().m() class Class4(Class2, Class3): def m(self): print("In Class4") super().m() obj = Class4() obj.m()
Producción:
In Class4 In Class2 In Class3 In Class1
Super() generalmente se usa con la función __init__ cuando se inicializan las instancias. La súper función llega a una conclusión, sobre qué método llamar con la ayuda de la orden de resolución de métodos (MRO) .
Orden de resolución del método:
En Python, cada clase, ya sea integrada o definida por el usuario, se deriva de la clase de objeto y todos los objetos son instancias del objeto de clase. Por lo tanto, la clase de objeto es la clase base para todas las demás clases.
En el caso de la herencia múltiple, primero se busca un atributo determinado en la clase actual; si no se encuentra, se busca en las clases principales. Las clases principales se buscan de izquierda a derecha y cada clase se busca una vez.
Si vemos el ejemplo anterior, el orden de búsqueda de los atributos será Derivado, Base1, Base2, objeto. El orden que se sigue se conoce como linealización de la clase Derivado y este orden se determina mediante un conjunto de reglas llamado Orden de resolución de métodos (MRO).
Para ver el MRO de una clase:
- Use el método mro(), devuelve una lista, por
ejemplo. Clase4.mro() - Usa el atributo _mro_, devuelve una tupla
Ej. Clase4.__mro__
Ejemplo:
Python3
# Python program to demonstrate # super() class Class1: def m(self): print("In Class1") class Class2(Class1): def m(self): print("In Class2") super().m() class Class3(Class1): def m(self): print("In Class3") super().m() class Class4(Class2, Class3): def m(self): print("In Class4") super().m() print(Class4.mro()) #This will print list print(Class4.__mro__) #This will print tuple
Producción:
[<clase ‘__principal__.Clase4’>, <clase ‘__principal__.Clase2’>, <clase ‘__principal__.Clase3’>, <clase ‘__principal__.Clase1’>, <clase ‘objeto’>]
(<clase ‘__principal__. Class4’>, <class ‘__main__.Class2’>, <class ‘__main__.Class3’>, <class ‘__main__.Class1’>, <class ‘object’>)