Programación Orientada a Objetos — Python

Ing. Bernardo Prado · DSM3 · UTH 2026-2

🎓 2026-2 🐍 Python 3 📊 20 pts

📝 Ejercicios 01 y 02 — POO Básica

Módulo de práctica: Clase con atributo de clase, constructor, métodos y representación __str__. Resuelve cada ejercicio implementando el código en Python 3.

2Ejercicios
20Puntos
U1Unidad
30Min aprox.

📌 Instrucciones

01

Sistema de Videoteca

🎯 10 pts📦 Clase + atrib. de clase🔗 Práctica U1

📋 Escenario

Una videoteca gestiona su catálogo. Cada Pelicula tiene código, título, director y género. El sistema limita a 5 alquileres simultáneos por película. Implementa: hay_disponibilidad(), alquilar(), devolver() y __str__ con operador ternario.

🧠 Lógica de cada método — cómo construirlo

__init__()
Recibe codigo, titulo, director, genero y guarda cada uno con self.x = x. Además inicializa self.alquileres_activos = 0 (contador en cero al crear la película).
hay_disponibilidad()
Un solo return con la comparación: return self.alquileres_activos < Pelicula.MAXIMO_ALQUILERES. Si hay menos de 5 alquileres activos → True; si ya se alcanzó el límite → False.
alquilar()
  1. Llamar if self.hay_disponibilidad():
  2. Si hay disponibilidad → self.alquileres_activos += 1 y return True.
  3. Fuera del ifreturn False (sin cupo).
devolver()
  1. if self.alquileres_activos > 0: — solo devuelve si hay algo activo.
  2. Si self.alquileres_activos -= 1 y return True.
  3. Fuera → return False (nada que devolver).
__str__()
Operador ternario primero: disp = "Sí" if self.hay_disponibilidad() else "No". Luego return un f-string multilinea con código, título, director, género, alquileres activos/MAXIMO y la variable disp.

📐 Diagrama de Clases

Pelicula
Atributo de clase
+ MAXIMO_ALQUILERES : int = 5
Instancia
+ codigo : str
+ titulo : str
+ director : str
+ genero : str
+ alquileres_activos : int = 0
Métodos
+ hay_disponibilidad() : bool
+ alquilar() : bool
+ devolver() : bool
+ __str__() : str

👤 Diagrama de Casos de Uso

«Sistema Videoteca» Cliente Consultar catálogo Alquilar película Devolver película Ver disponibilidad
▶ Comprobación — Salida esperada
[V001] Interestelar | Dir: Nolan | Género: Sci-Fi | Alquileres: 1/5 | Disponible: Sí
[V002] Parasite | Dir: Bong Joon-ho | Género: Drama | Alquileres: 0/5 | Disponible: Sí
[V003] Dune | Dir: Villeneuve | Género: Aventura | Alquileres: 1/5 | Disponible: Sí
📝 Respuesta completa — Código Python con explicación de cada línea
✅ Solución — Python 3 · videoteca.py Ejercicio 01
# ══════════════════════════════════════════════════════════════════════
# EJERCICIO 01 — Sistema de Videoteca
# ══════════════════════════════════════════════════════════════════════

class Pelicula:                              # Define la clase Pelicula: es el molde para crear objetos película
    MAXIMO_ALQUILERES = 5                   # Atributo de CLASE: límite global de 5 alquileres simultáneos
                                             # Al ser de clase, es compartido por TODOS los objetos Pelicula

    def __init__(self, codigo, titulo, director, genero):  # Constructor: Python lo llama automáticamente al hacer Pelicula(...)
        self.codigo             = codigo    # Almacena el código identificador (p.ej. "V001") en el objeto
        self.titulo             = titulo    # Almacena el título de la película (p.ej. "Interestelar")
        self.director           = director  # Almacena el nombre del director (p.ej. "Nolan")
        self.genero             = genero    # Almacena el género cinematográfico (p.ej. "Sci-Fi")
        self.alquileres_activos = 0         # Contador de alquileres en curso; inicia en 0 al crear el objeto

    def hay_disponibilidad(self):           # Método: comprueba si el contador aún no alcanzó el límite
        return self.alquileres_activos < Pelicula.MAXIMO_ALQUILERES  # True si activos < 5 (hay cupo) | False si ya se llegó a 5

    def alquilar(self):                      # Método: registra un nuevo alquiler si existe disponibilidad
        if self.hay_disponibilidad():        # Reutiliza hay_disponibilidad() para verificar si hay cupo
            self.alquileres_activos += 1    # Hay cupo: incrementa el contador en 1 registrando el alquiler
            return True                     # Retorna True: informa al llamador que el alquiler fue exitoso
        return False                         # Sin cupo: retorna False indicando que no se pudo alquilar

    def devolver(self):                      # Método: registra la devolución de un ejemplar alquilado
        if self.alquileres_activos > 0:     # Solo procede si hay al menos 1 alquiler activo que devolver
            self.alquileres_activos -= 1    # Hay activos: decrementa el contador en 1 liberando el alquiler
            return True                     # Retorna True: devolución realizada con éxito
        return False                         # Sin activos: retorna False, no había nada que devolver

    def __str__(self):                       # Método especial: Python lo invoca automáticamente con print(objeto)
        disp = "Sí" if self.hay_disponibilidad() else "No"  # Operador ternario: "Sí" si hay cupo, "No" si el límite fue alcanzado
        return (                             # El paréntesis permite escribir el f-string en múltiples líneas
            f"[{self.codigo}] {self.titulo} | "                        # Código entre [ ] y título de la película
            f"Dir: {self.director} | "                                 # Nombre del director con etiqueta "Dir:"
            f"Género: {self.genero} | "                                # Género con etiqueta "Género:"
            f"Alquileres: {self.alquileres_activos}/{Pelicula.MAXIMO_ALQUILERES} | "  # Activos / máximo (p.ej. 1/5)
            f"Disponible: {disp}"                                       # Disponibilidad evaluada con el ternario
        )                                    # Las f-strings contiguas dentro de () se concatenan en una sola cadena

# ── Programa principal ──────────────────────────────────────────────
p1 = Pelicula("V001", "Interestelar", "Nolan", "Sci-Fi")    # Crea objeto p1; __init__ guarda 4 atributos e inicia alquileres_activos=0
p2 = Pelicula("V002", "Parasite", "Bong Joon-ho", "Drama")  # Crea objeto p2 con los datos de Parasite; alquileres_activos=0
p3 = Pelicula("V003", "Dune", "Villeneuve", "Aventura")    # Crea objeto p3 con los datos de Dune; alquileres_activos=0

p1.alquilar()  # alquilar() → hay_disponibilidad()=True → alquileres_activos pasa 0→1 → retorna True
p3.alquilar()  # alquilar() → hay_disponibilidad()=True → alquileres_activos pasa 0→1 → retorna True
               # p2 NO se alquila → su alquileres_activos permanece en 0

print(p1)      # → "[V001] Interestelar | Dir: Nolan | Género: Sci-Fi | Alquileres: 1/5 | Disponible: Sí"
print(p2)      # → "[V002] Parasite | Dir: Bong Joon-ho | Género: Drama | Alquileres: 0/5 | Disponible: Sí"
print(p3)      # → "[V003] Dune | Dir: Villeneuve | Género: Aventura | Alquileres: 1/5 | Disponible: Sí"
02

Nómina de Empleados

🎯 10 pts📦 Constructor + __str__ + lista🔗 Práctica U1

📋 Escenario

Una empresa calcula la nómina de empleados. Cada Empleado tiene ID, nombre, departamento y salario bruto. El sistema aplica un 15% de bono a empleados con salario > 15,000 y descuento fiscal del 15%. Muestra la nómina completa iterando la lista con for.

🧠 Lógica de cada método — cómo construirlo

__init__()
Recibe id_empleado, nombre, departamento, salario_bruto y guarda cada uno. Agrega self.tiene_bono = False — empieza sin bono hasta que aplicar_bono() lo active.
calcular_neto()
  1. neto = self.salario_bruto * (1 - Empleado.DESCUENTO_FISCAL) — aplica el 15% de descuento fiscal.
  2. if self.tiene_bono: neto *= (1 + Empleado.BONO_PORCENTAJE) — si aplica bono, incrementa el 15% adicional.
  3. return round(neto, 2)
aplicar_bono()
if self.salario_bruto > 15000: self.tiene_bono = True. Solo activa la bandera; el cálculo real ocurre en calcular_neto(). No retorna nada.
__str__()
Ternario para el texto del bono: bono_txt = "✓ Bono" if self.tiene_bono else "✗ Sin bono". Luego f-string con ID, nombre, departamento, salario bruto, resultado de calcular_neto() y bono_txt.
for en main
Itera la lista nomina llamando primero emp.aplicar_bono() y luego print(emp) — en ese orden, porque __str__ usa tiene_bono que debe estar activado antes de imprimir.

📐 Diagrama de Clases

Empleado
Atributos de clase
+ BONO_PORCENTAJE : float = 0.15
+ DESCUENTO_FISCAL : float = 0.15
Instancia
+ id_empleado : str
+ nombre : str
+ departamento : str
+ salario_bruto : float
+ tiene_bono : bool = False
Métodos
+ calcular_neto() : float
+ aplicar_bono() : None
+ __str__() : str

🔄 Diagrama de Secuencia

main emp:Empleado Empleado('Luis','TI',18000) → objeto creado calcular_neto() → 15300.0 aplicar_bono() → tiene_bono=True print(emp) → __str__() → '[E001] Luis | Neto...'
▶ Comprobación — Salida esperada
[E001] Luis Ramos | TI | Bruto: $18000 | Neto: $17595.0 | ✓ Bono
[E002] Ana Torres | RRHH | Bruto: $12000 | Neto: $10200.0 | ✗ Sin bono
[E003] Carlos Paz | TI | Bruto: $20000 | Neto: $19550.0 | ✓ Bono
📝 Respuesta completa — Código Python con explicación de cada línea
✅ Solución — Python 3 · nomina.py Ejercicio 02
# ══════════════════════════════════════════════════════════════════════
# EJERCICIO 02 — Nómina de Empleados
# ══════════════════════════════════════════════════════════════════════

class Empleado:                             # Define la clase Empleado: modela a un trabajador y calcula su nómina
    BONO_PORCENTAJE  = 0.15                # Atributo de CLASE: 15% de bono para quienes superen $15,000 bruto
    DESCUENTO_FISCAL = 0.15                # Atributo de CLASE: 15% de descuento fiscal aplicado a todos

    def __init__(self, id_empleado, nombre, departamento, salario_bruto):  # Constructor: se ejecuta al hacer Empleado(...)
        self.id_empleado   = id_empleado   # Guarda el identificador único del empleado (p.ej. "E001")
        self.nombre        = nombre        # Guarda el nombre completo del empleado (p.ej. "Luis Ramos")
        self.departamento  = departamento  # Guarda el área de trabajo del empleado (p.ej. "TI" o "RRHH")
        self.salario_bruto = salario_bruto  # Guarda el salario antes de descuentos o bonos (p.ej. 18000)
        self.tiene_bono    = False          # Bandera booleana; inicia en False → aplicar_bono() la activa si corresponde

    def calcular_neto(self):                # Método: calcula el salario que el empleado recibirá efectivamente
        neto = self.salario_bruto * (1 - Empleado.DESCUENTO_FISCAL)  # Paso 1: aplica 15% de descuento fiscal al bruto
        if self.tiene_bono:                 # Paso 2: verifica si la bandera de bono fue activada
            neto *= (1 + Empleado.BONO_PORCENTAJE)  # Si sí: incrementa el neto en 15% adicional de bono
        return round(neto, 2)              # Retorna el salario neto redondeado a 2 decimales

    def aplicar_bono(self):                # Método: activa la bandera de bono si el salario supera los 15,000
        if self.salario_bruto > 15000:     # Solo para salarios brutos mayores estrictamente a 15,000
            self.tiene_bono = True         # Activa la bandera; calcular_neto() la leerá para ajustar el monto

    def __str__(self):                      # Método especial: Python lo invoca automáticamente con print(objeto)
        bono_txt = "✓ Bono" if self.tiene_bono else "✗ Sin bono"  # Ternario: texto descriptivo según el estado del bono
        return (                            # El paréntesis permite dividir el f-string en varias líneas
            f"[{self.id_empleado}] {self.nombre} | "   # ID entre [ ] y nombre completo del empleado
            f"{self.departamento} | "                  # Departamento al que pertenece el empleado
            f"Bruto: ${self.salario_bruto} | "         # Salario bruto original sin ningún ajuste
            f"Neto: ${self.calcular_neto()} | "        # Llama calcular_neto() en tiempo real → aplica descuento y bono
            f"{bono_txt}"                              # Texto del ternario: "✓ Bono" o "✗ Sin bono"
        )                                   # Las f-strings contiguas dentro de () se concatenan en una sola cadena

# ── Programa principal ──────────────────────────────────────────────
nomina = [                                 # Lista que agrupa los tres objetos Empleado del sistema de nómina
    Empleado("E001", "Luis Ramos",  "TI",   18000),  # Salario 18000 > 15000 → aplicar_bono() activará tiene_bono=True
    Empleado("E002", "Ana Torres",  "RRHH", 12000),  # Salario 12000 ≤ 15000 → tiene_bono permanece en False
    Empleado("E003", "Carlos Paz",  "TI",   20000),  # Salario 20000 > 15000 → aplicar_bono() activará tiene_bono=True
]

for emp in nomina:             # Itera sobre cada objeto Empleado de la lista nomina
    emp.aplicar_bono()         # PRIMERO: evalúa y activa tiene_bono si el salario supera 15,000
    print(emp)                 # DESPUÉS: llama __str__(); tiene_bono ya está evaluado → salida correcta

# Verificación de cálculos:
# E001: 18000 × 0.85 = 15300.0 → con bono: 15300 × 1.15 = 17595.0  ✓
# E002: 12000 × 0.85 = 10200.0 → sin bono: neto = 10200.0           ✓
# E003: 20000 × 0.85 = 17000.0 → con bono: 17000 × 1.15 = 19550.0  ✓