Clases en Python — Parte III 🌌
Herencia múltiple, ABC, polimorfismo, duck typing, extensión de built-ins y dataclasses
🌌 Consejo de los Sabios
Cerramos con herencia multinivel y múltiple , un ejemplo “bueno” de herencia, clases abstractas , polimorfismo y duck typing , cómo extender tipos incorporados , y dataclasses para datos inmutables o simples.
15) Herencia multinivel y 16) múltiple
class SerVivo:
def info(self ): return "ser vivo"
class Mamifero(SerVivo): # multinivel
def info(self ): return super ().info() + " → mamífero"
class Volador:
def vuela(self ): return "vuela"
class Murcielago(Mamifero, Volador): # múltiple
pass
m = Murcielago()
print (m.info(), m.vuela())
Nota: Orden de resolución de métodos (MRO ) gobierna cómo se buscan atributos en herencia múltiple.
17) Buen ejemplo de herencia
class Repositorio:
def guardar(self , entidad): raise NotImplementedError
class RepoEnMemoria(Repositorio):
def __init__ (self ): self ._data = []
def guardar(self , entidad): self ._data.append(entidad)
class RepoArchivo(Repositorio):
def __init__ (self , ruta): self ._ruta = ruta
def guardar(self , entidad): open (self ._ruta, "a" ).write(str (entidad)+ " \n " )
Criterio: heredar cuando hay una relación “es-un” clara y se comparte contrato (interfaz).
18) Clases abstractas (abc.ABC)
from abc import ABC, abstractmethod
class Figura(ABC):
@abstractmethod
def area(self ): ...
class Rectangulo(Figura):
def __init__ (self , a, b): self .a= a; self .b= b
def area(self ): return self .a * self .b
Beneficio: asegurar que las subclases implementen métodos requeridos .
19) Polimorfismo y 20) Duck typing
def imprimir_area(figura):
# Duck typing: “si tiene area(), sirve”
print ("Área:" , figura.area())
class Circulo:
def __init__ (self , r): self .r = r
def area(self ): return 3.14159 * self .r * self .r
imprimir_area(Rectangulo(2 ,3 ))
imprimir_area(Circulo(1.5 ))
Clave en Python: el tipo estructural (métodos disponibles) prima sobre la jerarquía formal.
21) Extender tipos incorporados
class ListaConSuma(list ):
def suma(self ):
return sum (self )
nums = ListaConSuma([1 ,2 ,3 ])
print (nums.suma())
Advertencia: heredar de built-ins es conveniente pero considera composición si necesitas mayor control.
22) Data classes (@dataclass)
from dataclasses import dataclass
@dataclass (frozen= True ) # inmutable; genera __init__, __repr__, __eq__
class Punto:
x: float
y: float
p = Punto(1.0 , 2.0 )
print (p) # Punto(x=1.0, y=2.0)
Ventaja: menos código ceremonial para objetos de datos ; frozen=True facilita inmutabilidad.
💭 Checkpoint (reflexión)
¿Qué problema resuelve una clase abstracta frente a solo documentar una interfaz?
Da un ejemplo donde duck typing sea preferible a herencia.
¿Cuándo preferirías una dataclass inmutable (frozen=True)?