Volver al curso

Python Desde Cero

leccion
15 / 21
beginner
20 horas
Programacion Orientada a Objetos

Herencia y Polimorfismo en Python

Lectura
25 min~4 min lectura

Herencia y Polimorfismo en Python

La herencia permite crear nuevas clases basadas en clases existentes, reutilizando y extendiendo su funcionalidad. El polimorfismo permite que objetos de diferentes clases respondan al mismo metodo de maneras distintas.

Herencia basica
class Animal:
    def __init__(self, nombre, especie):
        self.nombre = nombre
        self.especie = especie
        self.energia = 100
    
    def comer(self, alimento):
        self.energia += 20
        print(f'{self.nombre} come {alimento}. Energia: {self.energia}')
    
    def dormir(self):
        self.energia += 30
        print(f'{self.nombre} duerme. Energia: {self.energia}')
    
    def hacer_sonido(self):
        print('...')


class Perro(Animal):  # Hereda de Animal
    def __init__(self, nombre, raza):
        super().__init__(nombre, 'Canis lupus familiaris')
        self.raza = raza
    
    def hacer_sonido(self):  # Sobreescribe metodo
        print(f'{self.nombre} dice: Guau guau!')
    
    def traer_pelota(self):  # Nuevo metodo
        print(f'{self.nombre} trae la pelota!')


class Gato(Animal):
    def __init__(self, nombre, es_interior=True):
        super().__init__(nombre, 'Felis catus')
        self.es_interior = es_interior
    
    def hacer_sonido(self):
        print(f'{self.nombre} dice: Miau')
    
    def ronronear(self):
        print(f'{self.nombre} ronronea...')


perro = Perro('Rex', 'Labrador')
gato = Gato('Michi')

perro.comer('croquetas')  # Heredado de Animal
perro.hacer_sonido()      # Sobreescrito en Perro
perro.traer_pelota()      # Propio de Perro

gato.hacer_sonido()
gato.dormir()             # Heredado de Animal
La funcion super()
class Vehiculo:
    def __init__(self, marca, modelo, anio):
        self.marca = marca
        self.modelo = modelo
        self.anio = anio
    
    def info(self):
        return f'{self.anio} {self.marca} {self.modelo}'


class Coche(Vehiculo):
    def __init__(self, marca, modelo, anio, puertas=4):
        super().__init__(marca, modelo, anio)
        self.puertas = puertas
    
    def info(self):
        base = super().info()
        return f'{base} ({self.puertas} puertas)'


class CocheElectrico(Coche):
    def __init__(self, marca, modelo, anio, bateria_kwh):
        super().__init__(marca, modelo, anio)
        self.bateria_kwh = bateria_kwh
        self.carga = 100
    
    def info(self):
        base = super().info()
        return f'{base} - Electrico ({self.bateria_kwh} kWh)'
    
    def cargar(self, porcentaje):
        self.carga = min(100, self.carga + porcentaje)
        print(f'Cargando... Bateria al {self.carga}%')


v = Vehiculo('Generic', 'Model', 2020)
c = Coche('Toyota', 'Corolla', 2023)
e = CocheElectrico('Tesla', 'Model 3', 2024, 75)

print(v.info())
print(c.info())
print(e.info())
Polimorfismo

El mismo metodo, diferentes comportamientos segun el objeto:

class Forma:
    def area(self):
        raise NotImplementedError('Implementar en subclase')
    
    def describir(self):
        print(f'Soy {type(self).__name__}')
        print(f'Area: {self.area():.2f}')


class Rectangulo(Forma):
    def __init__(self, base, altura):
        self.base = base
        self.altura = altura
    
    def area(self):
        return self.base * self.altura


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


class Triangulo(Forma):
    def __init__(self, base, altura):
        self.base = base
        self.altura = altura
    
    def area(self):
        return (self.base * self.altura) / 2


formas = [Rectangulo(10, 5), Circulo(7), Triangulo(6, 4)]

for forma in formas:
    forma.describir()

area_total = sum(f.area() for f in formas)
print(f'Area total: {area_total:.2f}')
Clases abstractas
from abc import ABC, abstractmethod

class DispositivoPago(ABC):
    @abstractmethod
    def cobrar(self, monto):
        pass
    
    @abstractmethod
    def reembolsar(self, monto):
        pass
    
    def generar_recibo(self, monto, tipo):
        print(f'Recibo: {tipo} de {monto}')


class TarjetaCredito(DispositivoPago):
    def __init__(self, numero, limite):
        self.numero = numero[-4:]
        self.limite = limite
        self.usado = 0
    
    def cobrar(self, monto):
        if self.usado + monto > self.limite:
            raise ValueError('Limite excedido')
        self.usado += monto
        self.generar_recibo(monto, 'Cargo a tarjeta')
    
    def reembolsar(self, monto):
        self.usado -= monto
        self.generar_recibo(monto, 'Reembolso a tarjeta')


class Paypal(DispositivoPago):
    def __init__(self, email, saldo):
        self.email = email
        self.saldo = saldo
    
    def cobrar(self, monto):
        if monto > self.saldo:
            raise ValueError('Saldo insuficiente')
        self.saldo -= monto
        self.generar_recibo(monto, 'Cargo PayPal')
    
    def reembolsar(self, monto):
        self.saldo += monto
        self.generar_recibo(monto, 'Reembolso PayPal')


def procesar_compra(dispositivo, monto):
    try:
        dispositivo.cobrar(monto)
        print(f'Compra de {monto} procesada')
    except ValueError as e:
        print(f'Error: {e}')

tarjeta = TarjetaCredito('4532123456789012', 5000)
paypal = Paypal('[email protected]', 300)

procesar_compra(tarjeta, 150)
procesar_compra(paypal, 200)
procesar_compra(paypal, 500)  # Error
Herencia multiple
class Nadador:
    def nadar(self):
        print(f'{self.nombre} nada')

class Corredor:
    def correr(self):
        print(f'{self.nombre} corre')

class Triathleta(Nadador, Corredor):
    def __init__(self, nombre):
        self.nombre = nombre
    
    def competir(self):
        self.nadar()
        self.correr()
        print(f'{self.nombre} cruza la meta!')

atleta = Triathleta('Ana')
atleta.competir()
💡 Concepto Clave

Revisemos los puntos más importantes de esta lección antes de continuar.

Resumen

  • La herencia crea clases basadas en otras, reutilizando codigo
  • super() llama metodos de la clase padre
  • El polimorfismo permite diferentes comportamientos con el mismo metodo
  • Las clases abstractas (ABC) obligan a implementar ciertos metodos
  • Python soporta herencia multiple

En la proxima leccion: metodos especiales.

🧠 Pon a prueba tu conocimiento
¿Cuál es el aspecto más importante que aprendiste en esta lección?
  • Comprendo el concepto principal y puedo explicarlo con mis palabras
  • Entiendo cómo aplicarlo en mi situación específica
  • Necesito repasar algunas partes antes de continuar
  • Quiero ver más ejemplos prácticos del tema
✅ ¡Excelente! Continúa con la siguiente lección para profundizar más.