Herencia
Vamos a ver Herencia, Clases Abstractas y Polimorfismo en Python, explicados paso a paso y con ejemplos detallados, para que lo entiendas perfectamente.
🧬 1. Herencia en Python
La herencia permite crear una clase nueva a partir de una clase existente, reutilizando código.
🧱 Sintaxis básica:
class ClasePadre:
# atributos y métodos
class ClaseHija(ClasePadre):
# hereda todo de ClasePadre
✅ Ejemplo: Clase Animal
→ Clase Perro
class Animal:
def __init__(self, nombre):
self.nombre = nombre
def hablar(self):
print("El animal hace un sonido")
class Perro(Animal):
def hablar(self):
print(f"{self.nombre} dice: Guau!")
# Uso
animal = Animal("AnimalGenérico")
animal.hablar()
perro = Perro("Firulais")
perro.hablar()
🧠 Observa:
Perro
hereda deAnimal
.- El método
hablar()
enPerro
sobrescribe (override) al deAnimal
.
🧩 2. Clases Abstractas en Python
Las clases abstractas definen una estructura base pero no se pueden instanciar directamente. Se usan como plantillas.
🧰 ¿Cómo se hacen?
Se utiliza el módulo abc
(Abstract Base Classes).
from abc import ABC, abstractmethod
class Figura(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimetro(self):
pass
⚠️ Importante:
Figura
no se puede instanciar.- Cualquier clase hija debe implementar
area()
yperimetro()
.
✅ Ejemplo: Clase abstracta Figura
→ Clases Rectángulo
y Círculo
from abc import ABC, abstractmethod
import math
class Figura(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimetro(self):
pass
class Rectangulo(Figura):
def __init__(self, ancho, alto):
self.ancho = ancho
self.alto = alto
def area(self):
return self.ancho * self.alto
def perimetro(self):
return 2 * (self.ancho + self.alto)
class Circulo(Figura):
def __init__(self, radio):
self.radio = radio
def area(self):
return math.pi * self.radio ** 2
def perimetro(self):
return 2 * math.pi * self.radio
# Uso
formas = [Rectangulo(3, 4), Circulo(5)]
for f in formas:
print(f"Área: {f.area():.2f} | Perímetro: {f.perimetro():.2f}")
🧠 3. Polimorfismo
El polimorfismo permite usar el mismo método en distintas clases con comportamientos diferentes.
✅ Ejemplo de polimorfismo (continuando el de arriba):
def describir_figura(figura: Figura):
print(f"Área: {figura.area():.2f}, Perímetro: {figura.perimetro():.2f}")
# Uso
describir_figura(Rectangulo(5, 2))
describir_figura(Circulo(3))
Aunque ambas clases tienen métodos area()
y perimetro()
, se comportan diferente, eso es polimorfismo en acción.
📚 Resumen
Concepto | ¿Qué hace? |
---|---|
Herencia | Permite que una clase herede de otra |
super() |
Llama al constructor o método de la clase padre |
Clase abstracta | Clase que no se puede instanciar y define métodos obligatorios |
@abstractmethod |
Marca un método que debe ser implementado en clases hijas |
Polimorfismo | Permite usar una misma interfaz (método) con diferentes comportamientos |
Vamos a completar el tema viendo cómo usar super()
para heredar constructores y cómo funciona la herencia múltiple en Python, todo con ejemplos claros.
🧭 1. Uso de super()
para heredar el constructor
Cuando una clase hija necesita usar el constructor de su clase padre, se utiliza super()
.
✅ Ejemplo: Clase Empleado
hereda de Persona
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
class Empleado(Persona):
def __init__(self, nombre, edad, puesto):
super().__init__(nombre, edad) # llama al constructor de Persona
self.puesto = puesto
def mostrar_info(self):
print(f"{self.nombre}, {self.edad} años, trabaja como {self.puesto}")
# Uso
emp = Empleado("Laura", 30, "Diseñadora")
emp.mostrar_info()
🔍 ¿Qué hace super()
?
Llama al constructor de la clase base (Persona.__init__()
), para no repetir código y mantener herencia adecuada.
🧬 2. Herencia múltiple
Python sí permite que una clase herede de más de una clase.
class A:
def metodo_a(self):
print("Método A")
class B:
def metodo_b(self):
print("Método B")
class C(A, B): # hereda de A y B
def metodo_c(self):
print("Método C")
# Uso
obj = C()
obj.metodo_a() # de clase A
obj.metodo_b() # de clase B
obj.metodo_c() # de clase C
👀 ¿Qué tener en cuenta?
En herencia múltiple, Python usa el MRO (Method Resolution Order) para saber en qué orden buscar métodos en la jerarquía.
Puedes ver el MRO así:
print(C.__mro__)
⚠️ Ejemplo con conflicto de nombres (mismo método en dos padres)
class A:
def saludar(self):
print("Hola desde A")
class B:
def saludar(self):
print("Hola desde B")
class C(A, B): # A tiene prioridad en MRO
pass
obj = C()
obj.saludar() # → "Hola desde A"
Si cambias el orden de herencia:
class C(B, A):
pass
obj = C()
obj.saludar() # → "Hola desde B"
🧠 ¿Cuándo usar super()
en herencia múltiple?
Cuando varias clases padres tienen __init__()
y usas herencia múltiple, puedes coordinar los constructores así:
class A:
def __init__(self):
print("Inicializando A")
class B:
def __init__(self):
print("Inicializando B")
class C(A, B):
def __init__(self):
super().__init__() # solo llama a A por MRO
print("Inicializando C")
c = C()
print(C.__mro__)
Si quieres que todos los padres sean inicializados, deben usar también super()
correctamente, y heredar de object
o ABC
si son clases abstractas.