Objetivos de Aprendizaje
Al finalizar esta clase, serás capaz de:
- Crear jerarquías de clases usando herencia
- Usar
super()para llamar métodos de la clase padre - Sobreescribir métodos para especializar comportamiento
- Comprender el polimorfismo (mismo método, distinto comportamiento)
- Diseñar Usuario, Admin y Cliente para TaskFlow
Video Recomendado
Herencia y polimorfismo explicados:
Ver "Herencia y polimorfismo en Python" 12:15 minHerencia (20 min)
La herencia permite crear nuevas clases basadas en clases existentes. La clase hija hereda atributos y métodos del padre.
Sintaxis
# Clase Padre (Base)
class Animal:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
def hacer_sonido(self):
return "Sonido genérico"
def presentarse(self):
return f"Soy {self.nombre}, tengo {self.edad} años"
# Clase Hija (hereda de Animal)
class Perro(Animal):
def __init__(self, nombre, edad, raza):
# Llamar al constructor del padre
super().__init__(nombre, edad)
self.raza = raza
def hacer_sonido(self):
return "¡Guau!"
def buscar_pelota(self):
return f"{self.nombre} está buscando la pelota"
# Otra clase hija
class Gato(Animal):
def hacer_sonido(self):
return "¡Miau!"
# Uso
mi_perro = Perro("Fido", 3, "Labrador")
mi_gato = Gato("Michi", 2)
print(mi_perro.presentarse()) # Heredado de Animal
print(mi_perro.hacer_sonido()) # "¡Guau!" (especializado)
print(mi_gato.hacer_sonido()) # "¡Miau!" (especializado)
Jerarquía en TaskFlow
class Usuario:
"""Clase base para todos los usuarios."""
def __init__(self, username, email):
self.username = username
self.email = email
self.activo = True
def obtener_rol(self):
return "Usuario"
def puede_crear_proyectos(self):
return True
class Administrador(Usuario):
"""Admin hereda de Usuario."""
def obtener_rol(self):
return "Administrador"
def puede_eliminar_usuarios(self):
return True
def puede_crear_proyectos(self):
return True # También puede crear proyectos
class Cliente(Usuario):
"""Cliente hereda de Usuario."""
def __init__(self, username, email, empresa):
super().__init__(username, email)
self.empresa = empresa
def obtener_rol(self):
return "Cliente"
def puede_crear_proyectos(self):
return False # Los clientes solo ven proyectos
# Uso
admin = Administrador("admin", "admin@empresa.com")
cliente = Cliente("cliente1", "cli@empresa.com", "ACME Corp")
print(f"{admin.username} es {admin.obtener_rol()}")
print(f"{cliente.username} es {cliente.obtener_rol()} de {cliente.empresa}")
print(f"Admin puede eliminar usuarios: {admin.puede_eliminar_usuarios()}")
print(f"Cliente puede crear proyectos: {cliente.puede_crear_proyectos()}")
super() (10 min)
super() permite llamar métodos de la clase padre. Es útil en el constructor y para extender funcionalidad.
class Persona:
def __init__(self, nombre, edad):
print(f"Inicializando Persona: {nombre}")
self.nombre = nombre
self.edad = edad
def presentarse(self):
return f"Hola, soy {self.nombre}"
class Empleado(Persona):
def __init__(self, nombre, edad, salario):
# Llamar al __init__ del padre
super().__init__(nombre, edad)
print(f"Inicializando Empleado con salario: {salario}")
self.salario = salario
def presentarse(self):
# Extender el método del padre
base = super().presentarse()
return f"{base} y gano ${self.salario}"
# Uso
emp = Empleado("Juan", 30, 50000)
print(emp.presentarse())
# Salida:
# Inicializando Persona: Juan
# Inicializando Empleado con salario: 50000
# Hola, soy Juan y gano $50000
super().__init__() en el constructor de la clase hija para asegurar que todos los atributos del padre se inicialicen.
Sobreescritura de Métodos (10 min)
La sobreescritura (override) es redefinir un método del padre en la clase hija para cambiar su comportamiento.
class UsuarioBase:
def __init__(self, username):
self.username = username
def obtener_permisos(self):
return ["ver_tareas"]
def __str__(self):
return f"Usuario({self.username})"
class UsuarioPro(UsuarioBase):
def obtener_permisos(self):
# Extender: agregar permisos del padre + nuevos
permisos_base = super().obtener_permisos()
return permisos_base + ["crear_tareas", "editar_tareas"]
def __str__(self):
# Sobreescribir completamente
return f"UsuarioPro: @{self.username}"
class UsuarioEnterprise(UsuarioBase):
def obtener_permisos(self):
return ["ver_tareas", "crear_tareas", "editar_tareas",
"eliminar_tareas", "gestionar_usuarios"]
# Uso
usuario = UsuarioBase("basico")
pro = UsuarioPro("profesional")
enterprise = UsuarioEnterprise("empresa")
for u in [usuario, pro, enterprise]:
print(f"{u}: {u.obtener_permisos()}")
# Salida:
# Usuario(basico): ['ver_tareas']
# UsuarioPro: @profesional: ['ver_tareas', 'crear_tareas', 'editar_tareas']
# Usuario(empresa): ['ver_tareas', 'crear_tareas', ...]
Polimorfismo (10 min)
El polimorfismo significa "múltiples formas". El mismo método se comporta diferente según el objeto que lo ejecuta.
class Notificacion:
def enviar(self, mensaje):
raise NotImplementedError("Subclase debe implementar esto")
class NotificacionEmail(Notificacion):
def __init__(self, email):
self.email = email
def enviar(self, mensaje):
return f"📧 Enviando email a {self.email}: {mensaje}"
class NotificacionSMS(Notificacion):
def __init__(self, telefono):
self.telefono = telefono
def enviar(self, mensaje):
return f"📱 Enviando SMS a {self.telefono}: {mensaje}"
class NotificacionPush(Notificacion):
def __init__(self, device_id):
self.device_id = device_id
def enviar(self, mensaje):
return f"🔔 Enviando push a dispositivo {self.device_id}: {mensaje}"
# Función polimórfica
# Funciona con cualquier tipo de notificación
def notificar_usuario(notificacion, mensaje):
print(notificacion.enviar(mensaje))
# Uso
email = NotificacionEmail("usuario@email.com")
sms = NotificacionSMS("+123456789")
push = NotificacionPush("device123")
notificar_usuario(email, "Tarea completada!")
notificar_usuario(sms, "Recordatorio: reunión en 5 min")
notificar_usuario(push, "Nuevo mensaje recibido")
# También podemos iterar sobre diferentes tipos
notificaciones = [email, sms, push]
for n in notificaciones:
print(n.enviar("Mensaje de prueba"))
enviar().
Ejercicio: Jerarquía de Usuarios (20 min)
Crea una jerarquía completa para TaskFlow.
# jerarquia_usuarios.py
class Usuario:
"""Clase base para todos los usuarios."""
def __init__(self, username, email):
self._username = username
self._email = email
self._activo = True
@property
def username(self):
return self._username
@property
def email(self):
return self._email
@email.setter
def email(self, valor):
if "@" not in valor:
raise ValueError("Email inválido")
self._email = valor
def obtener_rol(self):
return "Usuario"
def obtener_permisos(self):
return ["ver_tareas", "comentar"]
def puede_eliminar_proyectos(self):
return False
def __str__(self):
return f"[{self.obtener_rol()}] @{self._username}"
class MiembroEquipo(Usuario):
"""Usuario que puede crear y editar tareas."""
def __init__(self, username, email, departamento):
super().__init__(username, email)
self.departamento = departamento
def obtener_rol(self):
return f"Miembro ({self.departamento})"
def obtener_permisos(self):
base = super().obtener_permisos()
return base + ["crear_tareas", "editar_tareas", "asignar_tareas"]
class Administrador(Usuario):
"""Admin con todos los permisos."""
def obtener_rol(self):
return "Administrador"
def obtener_permisos(self):
return ["ver_tareas", "comentar", "crear_tareas", "editar_tareas",
"eliminar_tareas", "gestionar_usuarios", "ver_reportes"]
def puede_eliminar_proyectos(self):
return True
class Cliente(Usuario):
"""Cliente externo, solo puede ver."""
def __init__(self, username, email, empresa):
super().__init__(username, email)
self.empresa = empresa
def obtener_rol(self):
return f"Cliente - {self.empresa}"
def obtener_permisos(self):
# Clientes solo ven, no comentan ni crean
return ["ver_tareas"]
# === PRUEBAS ===
if __name__ == "__main__":
# Crear diferentes tipos de usuarios
usuarios = [
Usuario("visitante", "visit@email.com"),
MiembroEquipo("desarrollador", "dev@email.com", "Tecnología"),
Administrador("admin", "admin@email.com"),
Cliente("cliente1", "cli1@empresa.com", "ACME Corp")
]
print("=== Jerarquía de Usuarios TaskFlow ===\n")
# Polimorfismo: mismo método, distinto comportamiento
for u in usuarios:
print(f"{u}")
print(f" Permisos: {', '.join(u.obtener_permisos())}")
print(f" Puede eliminar proyectos: {u.puede_eliminar_proyectos()}")
print()
# Función polimórfica
def mostrar_info_usuario(usuario):
"""Funciona con cualquier tipo de Usuario."""
print(f"Usuario: {usuario}")
print(f"Rol: {usuario.obtener_rol()}")
print(f"Total permisos: {len(usuario.obtener_permisos())}")
print("=== Info Detallada ===")
for u in usuarios:
mostrar_info_usuario(u)
print()
Retos Adicionales
- Agrega clase
Gerenteque herede deMiembroEquipoy pueda aprobar tareas - Crea método
tiene_permiso(permiso)que verifique si un usuario tiene un permiso específico - Agrega atributo
proyectos_asignadosaMiembroEquipo
Resumen
- Herencia: Clase Hija(Padre) - hereda atributos y métodos
- super(): Llama métodos del padre, especialmente
__init__ - Sobreescritura: Redefinir método del padre en la hija
- Polimorfismo: Mismo método, distinto comportamiento según la clase
- Jerarquía TaskFlow: Usuario → MiembroEquipo/Administrador/Cliente