Clases Abstractas

Clases Abstractas en Python

Las clases abstractas son clases que no se pueden instanciar directamente, sino que deben ser heredadas por otras clases. Sirven como "plantilla" para otras clases.

Concepto clave:

  • No se pueden crear objetos de una clase abstracta

  • Definen métodos que deben ser implementados por las clases hijas

  • Pueden contener implementación (métodos normales) y métodos abstractos (sin implementación)

Ejemplo muy sencillo:

python
from abc import ABC, abstractmethod

# Clase abstracta
class Animal(ABC):
    
    @abstractmethod
    def hacer_sonido(self):
        pass  # Sin implementación - las hijas deben implementarlo
    
    def dormir(self):
        print("Zzz... durmiendo")  # Método normal con implementación

# Clases hijas que SÍ se pueden instanciar
class Perro(Animal):
    def hacer_sonido(self):
        print("¡Guau guau!")

class Gato(Animal):
    def hacer_sonido(self):
        print("¡Miau miau!")

# Uso
mi_perro = Perro()
mi_gato = Gato()

mi_perro.hacer_sonido()  # ¡Guau guau!
mi_gato.hacer_sonido()   # Miau miau!
mi_perro.dormir()        # Zzz... durmiendo

# Esto daría ERROR:
# animal = Animal()  # TypeError: No se puede instanciar clase abstracta

¿Por qué usar clases abstractas?

  1. Forzar consistencia: Todas las clases hijas deben implementar los métodos abstractos

  2. Organizar código: Definir una estructura común para un grupo de clases

  3. Documentar: Mostrar claramente qué métodos deben existir

Otro ejemplo práctico:

python
from abc import ABC, abstractmethod

class Forma(ABC):
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimetro(self):
        pass

class Cuadrado(Forma):
    def __init__(self, lado):
        self.lado = lado
    
    def area(self):
        return self.lado * self.lado
    
    def perimetro(self):
        return 4 * self.lado

class Circulo(Forma):
    def __init__(self, radio):
        self.radio = radio
    
    def area(self):
        return 3.1416 * self.radio * self.radio
    
    def perimetro(self):
        return 2 * 3.1416 * self.radio

# Uso
cuadrado = Cuadrado(5)
print(f"Área del cuadrado: {cuadrado.area()}")  # 25

circulo = Circulo(3)
print(f"Área del círculo: {circulo.area()}")    # ~28.27

En resumen: Las clases abstractas son como contratos que definen qué deben hacer las clases hijas, pero no cómo lo hacen. 

Clases Abstractas en Python: La Fábrica de Juguetes 🏭🧸

Imagina que tienes una fábrica de juguetes. No produces juguetes genéricos, sino tipos específicos: carros, muñecas y rompecabezas.

La idea principal

Una clase abstracta es como el plano general de la fábrica:

python
from abc import ABC, abstractmethod

class Juguete(ABC):  # Este es nuestro "plano general"
    @abstractmethod
    def hacer_sonido(self):
        pass  # ¡No sabemos qué sonido hará cada juguete!
    
    @abstractmethod
    def mover(self):
        pass  # ¡No sabemos cómo se moverá cada juguete!

¿Por qué usar clases abstractas?

❌ NO PUEDES crear un "juguete genérico"

python
# Esto NO funciona - da error!
juguete_generico = Juguete()  # TypeError!

✅ SÍ PUEDES crear juguetes específicos

python
class Carro(Juguete):
    def hacer_sonido(self):
        return "¡Run run! 🚗"
    
    def mover(self):
        return "Rodando por el piso"

class Munieca(Juguete):
    def hacer_sonido(self):
        return "¡Hola! 👋"
    
    def mover(self):
        return "Caminando elegantemente"

Ejemplo completo: Nuestra fábrica en acción

python
from abc import ABC, abstractmethod

# El plano maestro (clase abstracta)
class Juguete(ABC):
    @abstractmethod
    def hacer_sonido(self):
        pass
    
    @abstractmethod
    def mover(self):
        pass
    
    # Método concreto - TODOS los juguetes lo heredan
    def presentarse(self):
        return f"Soy un juguete y {self.mover()}"

# Juguetes específicos
class Carro(Juguete):
    def hacer_sonido(self):
        return "¡Run run! 🚗"
    
    def mover(self):
        return "rodando por el piso"

class Munieca(Juguete):
    def hacer_sonido(self):
        return "¡Hola! 👋"
    
    def mover(self):
        return "caminando elegantemente"

# ¡A jugar!
carro_rojo = Carro()
munieca_lucia = Munieca()

print(carro_rojo.hacer_sonido())  # ¡Run run! 🚗
print(munieca_lucia.presentarse())  # Soy un juguete y caminando elegantemente

Analogía del restaurante 🍽️

Clase abstracta = Receta base de "pizza"

  • Obligatorio: tener masa, queso, ingredientes

  • Opcional: método para hornear (ya está implementado)

Clases concretas = Pizzas específicas

  • PizzaMargherita, PizzaPepperoni, PizzaHawaiana

  • Cada una define SUS ingredientes específicos

¿Cuándo usar clases abstractas?

  1. Cuando quieres un contrato: "Todos los que hereden de mí DEBEN implementar estos métodos"

  2. Para organizar código: Agrupar funcionalidad común

  3. Para evitar errores: Python te avisa si olvidas implementar un método obligatorio

Resumen visual

text
JUGUETE (Abstracta) ← No se puede instanciar
├── debe tener: hacer_sonido() ❗
├── debe tener: mover() ❗
└── ya tiene: presentarse() ✅
    │
    ├── CARRO (Concreta)
    │   ├── hacer_sonido() = "¡Run run!"
    │   └── mover() = "Rodando"
    │
    └── MUÑECA (Concreta)
        ├── hacer_sonido() = "¡Hola!"
        └── mover() = "Caminando"

¡Así garantizas que todos tus juguetes se comporten como juguetes



Comentarios

Entradas populares de este blog

¿Qué es un Closure?

4 tipos de colecciones de datos más

Funciones en Python: con y sin paréntesis