💰 Herencia
En herencia no se trata de ver la relación entre clases. Más bien, es decir esta clase es esta otra clase. Un Coche
es un Vehículo
.
La herencia es una característica de POO que permite a una clase heredar atributos y métodos de otra clase. La clase que hereda se llama clase derivada, clase hija o subclase, y la clase de la que se hereda se llama clase base, clase padre o superclase.
✏️ Ejemplos
class Padre:
pass
# Cuando añadimos una clase dentro de los paréntesis, estamos diciendo que Hijo va a heredar todos los métodos y atributos de Padre.
class Hijo(Padre):
pass
print(Hijo.__bases__) # Imprimir a su padre
print(Padre.__subclasses__()) # Imprimir a sus hijos
Esto lo podemos ver en el siguiente ejemplo:
class VehiculoConRuedas:
def __init__(self, ruedas, frenos):
self.ruedas = ruedas
self.frenos = frenos
def __str__(self):
return f"Este vehículo tiene {self.ruedas} ruedas y tiene frenos {self.frenos}"
class Moto(VehiculoConRuedas):
pass
unaMoto = Moto(2, True) # Como Moto no tiene constructor, todos los argumentos que coloquemos aquí pasarán directamente a la clase padre (VehiculoConRuedas)
# En esta línea se está utilizando el método __str__ de VehiculoConRuedas, ya que Moto lo hereda.
print(unaMoto) # Imprime: Este vehículo tiene 2 ruedas y tiene frenos True
🦸♂️ super()
Cuando queremos hacer referencia a la instancia de la clase padre desde una clase hija podemos utilizar el método super()
.
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
class Estudiante(Persona):
def __init__(self, nombre, edad, curso):
super().__init__(nombre, edad) # En esta línea estamos llamando al método constructor de Persona con sus argumentos correspondientes
self.curso = curso # De igual manera, podemos agregar más atributos que sólo estarán disponibles en Estudiante
# En total, la clase Estudiante tendrá los métodos y atributos de Persona más los que definamos en Estudiante
christopher = Estudiante("Christopher", 54, "Pre-primaria")
print(f"{christopher.nombre} tiene {christopher.edad} años y está cursando {christopher.curso}") # Imprime: "Christopher tiene 54 años y está cursando Pre-primaria"
🏆 Method Resolution Order (MRO)
El Method Resolution Order o en español "Orden de Resolución de Métodos" nos permite obtener el orden en el que se resuelven los métodos en relación a una herencia de clases. Podemos utilizar mro()
o el atributo __mro__
en cualquier clase para obtener una lista de las clases padres que hereda una clase hija, siendo la primera en la lista la que se evalue primero a la hora de ejecutar un método.
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
def __str__(self):
return f"{self.nombre} tiene {self.edad} años."
# Definimos un método saludar para Persona
def saludar(self):
print("Hola persona")
# Profesor hereda de Persona
class Profesor(Persona):
def __init__(self, nombre, edad, materia, sueldo):
super().__init__(nombre, edad)
self.materia = materia
self.sueldo = sueldo
# Definimos otro método saludar para Profesor
def saludar(self):
print("Hola profesor genérico")
def __str__(self):
return f"{super().__str__()} El profesor da la materia {self.materia} y le pagan ${self.sueldo}"
def aumentar(self, porcentaje):
self.sueldo += self.sueldo * (porcentaje / 100)
# ProfesorDePOO hereda de Profesor que a su vez hereda de Persona
class ProfesorDePOO(Profesor):
def __init__(self, nombre, edad, materia, sueldo):
super().__init__(nombre, edad, materia, sueldo)
# Definimos todavía otro método saludar para ProfesorDePOO
def saludar(self):
print("Hola profesor de POO")
unProfesor = ProfesorDePOO("Raul", 30, "Álgebra lineal", 10)
unProfesor.saludar() # En este caso se ejecuta el método saludar de ProfesorDePOO gracias al MRO
print(ProfesorDePOO.mro()) # Imprime: [<class '__main__.ProfesorDePOO'>, <class '__main__.Profesor'>, <class '__main__.Persona'>, <class 'object'>]
print(ProfesorDePOO.__mro__) # Imprime: (<class '__main__.ProfesorDePOO'>, <class '__main__.Profesor'>, <class '__main__.Persona'>, <class 'object'>)
print(unProfesor) # En este caso se ejectua el método __str__ de Profesor, ya que ProfesorDePOO no tiene uno definido.
🏯 Herencia multinivel
En el ejemplo anterior vimos un tipo de herencia que se da como un árbol genealógico: Padre
-> Hijo
-> Nieto
. La clase Persona
era heredada por la clase Profesor
que a su vez era heredada por la clase ProfesorDePOO
. A esto le llamamos herencia multinivel.