Este tutorial adapta pedagógicamente el Día 16. Las secciones 📝 Ejercicio original del curso provienen de los archivos del curso. Los retos 🟢🟡🟠🔴, el proyecto extra, el proyecto integrador y el kit de reemplazo de la máquina de café (Anexo A) son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.
⚠️ Prerequisito importante: este día retoma el proyecto de la máquina de café del Día 15, que se hizo sin objetos (con programación por procedimientos). Ese proyecto se desarrolla en el tutorial del Día 15 (
tutorial_dia15_100_dias_de_python.md). Si tus estudiantes no lo hicieron, basta con explicarles sus requisitos, que se resumen en la Sección 5.
Tabla de contenidos
- Antes de empezar: ¿por qué objetos?
- Clases y objetos: atributos y métodos
- Construir objetos y usarlos: la librería Turtle
- Paquetes externos: PyPI e instalación
- Práctica con PrettyTable: atributos y métodos
- 🚀 Proyecto del día: la Máquina de Café con POO
- 🌟 Proyecto extra: Tabla del Intercolegiado
- 🏆 Proyecto integrador del Día 16: Panel de la Cafetería Escolar
- 🤖 Programar con apoyo de IA
- 🛠️ Correcciones técnicas al material original
- 📋 Matriz de trazabilidad
- 📦 Evidencias de aprendizaje del Día 16
- 📎 Anexo A: Kit de reemplazo de la Máquina de Café
0. Antes de empezar: ¿por qué objetos?
(Fuentes: 108 - Why do we need OOP and how does it work-.md, 115 - Don't forget to review occasionally.md)
El problema: el código "espagueti"
Hasta ahora hemos programado de forma procedimental: funciones que se llaman unas a otras, de arriba hacia abajo. Es uno de los paradigmas más antiguos: lenguajes como Fortran y COBOL se basaban casi exclusivamente en él. Funciona bien en programas pequeños, pero cuando crecen, las relaciones entre funciones y variables se enredan como un plato de espaguetis. El curso lo compara, en broma, con una red de relaciones en la que "todos han estado con alguien más".
La idea: dividir en piezas que saben hacer su trabajo
Ejemplo 1: un carro autónomo. Es un proyecto enorme, pero se puede dividir en módulos: cámara, detección de carril, navegación y manejo del combustible.
- Cada equipo trabaja en su módulo al mismo tiempo que los demás.
- Los módulos son reutilizables: la cámara y la navegación servirían también para un dron de entregas.
Ejemplo 2: el restaurante. Si heredas un restaurante y lo manejas solo, tienes que ser recepcionista, mesero, chef y encargado de la limpieza a la vez. Solo funciona si el local es muy pequeño. Si contratas personal con roles definidos, tú solo eres el gerente: le dices al mesero que atienda la mesa 4 sin explicarle cómo atender, y al chef que cocine sin enseñarle a freír un huevo. Cada uno sabe hacer su trabajo.
Esa es la Programación Orientada a Objetos (POO): dividir el programa en "personajes" (objetos) que guardan sus propios datos y saben hacer sus propias tareas.
Consejo de cierre del curso: ver videos da la sensación de avanzar. Repasa con frecuencia: cambia los proyectos, rehaz los retos y escribe tú el código de los tutoriales.
Prerequisito general: funciones, módulos e
import(Días 4, 7 y 10), diccionarios (Día 9) y la Máquina de Café del Día 15.
1. Clases y objetos: atributos y métodos
(Fuente: 109 - How to use OOP- Classes and Objects.md)
🎯 Objetivo de aprendizaje
- Explicar qué son una clase, un objeto, un atributo y un método.
- Modelar un objeto de la vida real identificando qué tiene y qué hace.
📖 Explicación conceptual
Para modelar un mesero virtual nos preguntamos dos cosas:
| Pregunta | Nombre en POO | Se programa como… | Ejemplo |
|---|---|---|---|
| ¿Qué tiene? | Atributos | Variables unidas al objeto | sosteniendo_plato = True, mesas = [4, 5, 6] |
| ¿Qué hace? | Métodos | Funciones unidas al objeto | tomar_pedido(), recibir_pago() |
Un atributo es "una palabra elegante para una variable asociada a un objeto". Un método es "una función que puede hacer un objeto en particular".
Clase frente a objeto:
- La clase es el plano o molde: define qué tiene y qué hace un mesero.
- Los objetos son los meseros concretos creados a partir de ese plano, por ejemplo Henry y Betty. Se pueden crear tantos como se quiera.
flowchart LR
C["Clase Mesero<br/>(plano)"] --> O1["Objeto: henry"]
C --> O2["Objeto: betty"]
C --> O3["Objeto: ..."]Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: para una licuadora, escribe 3 atributos y 3 métodos.
- 🟡 Reto 2: para un estudiante del sistema académico del colegio, haz la tabla de atributos y métodos. ¿Cuáles serían los objetos concretos?
- 🟠 Reto 3: modela el restaurante completo: ¿qué clases hay? ¿Qué atributos y métodos tiene cada una? ¿Qué objeto "le pide cosas" a cuál?
- 🔴 Reto 4: toma tu Blackjack del Día 11 y propón cómo lo dividirías en clases (por ejemplo, Baraja, Mano, Jugador y Crupier). No escribas código todavía: solo el diseño con atributos y métodos.
2. Construir objetos y usarlos: la librería Turtle
(Fuente: 110 - Constructing Objects and Accessing their Attributes and Methods.md)
🎯 Objetivo de aprendizaje
- Construir un objeto a partir de una clase.
- Leer y modificar atributos, y llamar métodos, con la notación de punto.
- Usar la documentación para descubrir qué puede hacer un objeto.
📖 Explicación conceptual
Sintaxis para construir un objeto:
car = CarBlueprint()- La clase se escribe en PascalCase: cada palabra empieza con mayúscula y no hay guiones bajos (
CarBlueprint,PrettyTable). Así se distingue de las variables y funciones, que van en snake_case (my_screen). - Los paréntesis activan la construcción del objeto, igual que activan una función.
Notación de punto:
| Para… | Sintaxis | Ejemplo |
|---|---|---|
| Leer un atributo | objeto.atributo |
car.speed |
| Llamar un método | objeto.metodo() |
car.stop() |
Turtle. La librería de "gráficos de tortuga" viene incluida con Python: no hay que instalarla. Imagina una tortuga con un pincel en la espalda a la que le das órdenes para que dibuje en la pantalla.
from turtle import Turtle, Screen
timmy = Turtle() # construir un objeto Turtle
print(timmy) # <turtle.Turtle object at 0x...>: es un objeto, no un texto
timmy.shape("turtle") # método: cambiar la forma
timmy.color("coral") # método: cambiar el color
timmy.forward(100) # método: avanzar 100 pasos
my_screen = Screen()
print(my_screen.canvheight) # atributo: la altura del lienzo (300 por defecto)
my_screen.exitonclick() # método: mantener la ventana abierta hasta que se haga clicConsejo del curso: en la documentación oficial de Turtle (se abre en otra pestaña) están todos los métodos para moverse, dibujar y cambiar colores. Los colores se pueden escribir por su nombre en inglés, por ejemplo
"coral". Hay una lista de nombres de colores en la documentación de Tk.
Repaso de módulos (Días 4 y 7). import turtle y luego turtle.Turtle() es equivalente a from turtle import Turtle y luego Turtle().
⚠️ Errores frecuentes
- Olvidar los paréntesis al construir:
timmy = Turtleguarda la clase, no un objeto. Después,timmy.forward(100)falla con unTypeError. - Llamar
forwardsin argumento:TypeError: missing 1 required positional argument. - La ventana se cierra sola: falta
screen.exitonclick()al final. - Llamar tu archivo
turtle.py: "tapa" la librería. Es el mismo problema derandom.pydel Día 4.
📝 Ejercicio original del curso: tu primera tortuga
- Crea el objeto
timmyy el objetomy_screen. - Imprime el atributo
canvheightde la pantalla. - Cambia la forma a
"turtle"y el color a uno de la lista de la documentación. - Busca en la documentación cómo hacer que la tortuga avance 100 pasos.
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: crea dos tortugas de colores distintos y haz que avancen distancias diferentes.
- 🟡 Reto 2: busca en la documentación los métodos
left,right,penupypendown, y úsalos para escribir la inicial de tu nombre. - 🟠 Reto 3: cambia el atributo título de la ventana. (Pista: busca "title" en la sección de Screen.)
- 🔴 Reto 4: usando solo la documentación, dibuja una "estrella" de 5 puntas. ¿Qué ángulo necesitas? Explica el razonamiento geométrico. (El Día 18 se dedica completamente a Turtle.)
3. Paquetes externos: PyPI e instalación
(Fuente: 111 - How to Add Python Packages and use PyPi.md)
📖 Explicación conceptual
| Término | Qué es |
|---|---|
| Módulo | Un archivo .py. Cada archivo que creas es un módulo |
| Paquete | Un conjunto de muchos archivos escritos por otras personas para lograr un objetivo |
| PyPI (pypi.org (se abre en otra pestaña)) | El Python Package Index: el gran repositorio de paquetes que comparte la comunidad de Python |
A diferencia de Turtle, los paquetes de PyPI hay que instalarlos.
Formas de instalar prettytable:
| Método | Pasos |
|---|---|
| PyCharm (el que usa el curso) | File → Settings (Windows) o PyCharm → Preferences/Settings (Mac) → Project → Python Interpreter → botón + → buscar prettytable → Install Package |
| Terminal (cualquier editor) | pip install prettytable o python -m pip install prettytable |
Ver el código de un paquete: en PyCharm, clic derecho sobre el nombre → Go To → Implementation. El curso muestra que no necesitas entender ese código para usarlo; basta con leer la documentación.
🛠️ Nota técnica: el curso dice que la documentación de PrettyTable está alojada en Google Code Archive. Hoy la documentación actualizada está en la página del paquete en PyPI (se abre en otra pestaña) y en su repositorio de GitHub. Los ejemplos de este tutorial se probaron con PrettyTable 3.18.
4. Práctica con PrettyTable
(Fuente: 112 - Practice Modifying Object Attributes and Calling Methods.md)
🎯 Objetivo de aprendizaje
- Construir un objeto de una librería externa, llamar sus métodos y modificar sus atributos, guiándose por la documentación.
📝 Ejercicio original del curso: tabla de Pokémon
Enunciado:
- Construye un objeto
tablea partir de la clasePrettyTable. - Con el método
add_column, agrega la columna"Pokemon"con Pikachu, Squirtle y Charmander, y la columna"Type"con Electric, Water y Fire, en el mismo orden para que cada tipo corresponda a su Pokémon. - Imprime la tabla.
- Cambia el atributo
aligna"l"para alinear a la izquierda.
from prettytable import PrettyTable
table = PrettyTable()
table.add_column("Pokemon", ["Pikachu", "Squirtle", "Charmander"])
table.add_column("Type", ["Electric", "Water", "Fire"])
table.align = "l"
print(table)Resultado (verificado):
+------------+----------+
| Pokemon | Type |
+------------+----------+
| Pikachu | Electric |
| Squirtle | Water |
| Charmander | Fire |
+------------+----------+Lección clave:
table.add_column(...)es un método (lleva paréntesis y hace algo).table.align = "l"modifica un atributo (se asigna con=, como una variable).
🛠️ Nota técnica: en la versión actual de la librería,
print(table.align)muestra también una clave interna'base_align_value'además de las columnas. Es normal y no afecta el ejercicio.
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: crea una tabla de tus 3 materias favoritas con su profesor usando
add_rowen lugar deadd_column. (Pista: primerotable.field_names = ["Materia", "Profesor"].) - 🟡 Reto 2: ordena una tabla por una columna usando los atributos
sortbyyreversesort. - 🟠 Reto 3: busca en la documentación cómo cambiar el estilo de los bordes (por ejemplo
set_style) y prueba al menos dos estilos. - 🔴 Reto 4: investiga qué otros paquetes de PyPI podrían servir en el colegio (por ejemplo para generar códigos QR o gráficas). Elige uno, lee su documentación e identifica una clase, un atributo y un método.
5. 🚀 Proyecto del día: la Máquina de Café con POO
(Fuentes: 113 - Building the Coffee Machine in OOP.md, 114 - Walkthrough and Solution for the OOP Coffee Machine.md, proyecto oficial del curso original)
Contexto: la analogía del hotel (Steve Jobs)
El curso cita una explicación de Steve Jobs. Llegas a Japón con la camiseta manchada: no conoces la ciudad, no tienes yenes y no hablas japonés. Pero el hotel sí sabe dónde está la lavandería, tiene la moneda local y habla el idioma. Tú solo le entregas la camiseta y recibes una limpia. Así se trabaja con objetos: llamas a hotel.limpiar(camiseta) y confías en que el objeto sabe hacerlo, sin preocuparte por los detalles.
Requisitos (los mismos del Día 15)
- Preguntar "¿Qué quieres? (latte/espresso/cappuccino/)".
offapaga la máquina.reportimprime los recursos (agua, leche y café) y el dinero acumulado.- Verificar que haya suficientes recursos para la bebida.
- Procesar las monedas y verificar que el pago sea suficiente, entregando el cambio.
- Preparar el café, descontando los ingredientes.
La novedad
El curso entrega cuatro clases ya escritas, con su documentación. No debes modificarlas: trátalas "como si fueran una librería externa" y trabaja solo en main.py.
🛠️ Nota: el código inicial del curso (archivos
menu.py,coffee_maker.py,money_machine.py) y su sitio de documentación no están incluidos entre los materiales suministrados. En el Anexo A encontrarás un kit de reemplazo creado para esta adaptación, con la misma interfaz que documenta el curso, en pesos colombianos y probado.
Documentación de las clases (interfaz)
| Clase | Atributos | Métodos |
|---|---|---|
MenuItem |
name, cost, ingredients (diccionario) |
— |
Menu |
— | get_items() → texto "latte/espresso/cappuccino/"find_drink(order_name) → un MenuItem, o None si no existe |
CoffeeMaker |
— | report()is_resource_sufficient(drink) → True/Falsemake_coffee(order) |
MoneyMachine |
— | report()make_payment(cost) → True/False (pide las monedas y entrega el cambio) |
🔍 Antes de programar
- ¿Qué objetos necesitas crear? ¿A partir de qué clases?
- Para cada requisito (1 a 6), ¿qué método de qué objeto lo resuelve? Haz una tabla.
is_resource_sufficientespera unMenuItem, no un texto. ¿Cómo obtienes elMenuItema partir de lo que escribió el usuario?- ¿De dónde sale el costo que necesita
make_payment? (Pista: es un atributo.)
Construcción paso a paso (según la solución del curso)
Paso 1: el informe. Crea money_machine = MoneyMachine() y coffee_maker = CoffeeMaker(). La convención es nombrar el objeto como la clase, pero en snake_case. Llama a report() en los dos.
Paso 2: el menú y el bucle. Crea menu = Menu() y un while is_on:. Muestra las opciones con menu.get_items() dentro de una f-string. Maneja off y report.
Paso 3: encontrar la bebida. drink = menu.find_drink(choice). Imprímela para comprobar que es un objeto MenuItem.
Paso 4: recursos, pago y café. El curso llega a una solución muy compacta:
if coffee_maker.is_resource_sufficient(drink) and money_machine.make_payment(drink.cost):
coffee_maker.make_coffee(drink)Gracias al and, si no hay recursos, ni siquiera se piden las monedas: Python no evalúa la segunda condición si la primera es False.
"Incluso si nunca hubieras visto cómo funcionan los métodos por dentro, puedes entender con facilidad lo que hace este código."
Pruebas (con el kit del Anexo A)
| Acción | Resultado esperado (verificado con el kit) |
|---|---|
report al inicio |
Agua 300 ml, Leche 200 ml, Café 100 g, Dinero $0 |
latte pagando $5000 |
"Tu cambio es $0" y "Aquí está tu latte ☕" |
Otro latte |
"No hay suficiente agua" y "No hay suficiente leche", sin pedir monedas |
espresso pagando $2000 + $1000 |
Se prepara |
report |
Agua 50, Leche 50, Café 58, Dinero $8000 |
mocha (no existe) |
⚠️ AttributeError: 'NoneType' object has no attribute 'ingredients' |
🛠️ Nota técnica (verificada con el kit):
find_drinkdevuelveNonesi la bebida no existe. La solución del curso le pasa eseNoneais_resource_sufficient, y el programa se detiene. Corrección: verificar antes conif drink:o conif drink is not None:. Es otro caso del "camino que devuelveNone" (Días 10 y 12).
⭐ Extensión del proyecto (sin modificar las clases)
- Mostrar un mensaje de bienvenida con el menú y los precios (recorriendo los objetos del menú y leyendo
nameycost). - Contar cuántas bebidas de cada tipo se vendieron (un diccionario en
main.py). - Pregunta para el Día 17: ¿qué tendrías que cambiar en las clases para agregar una bebida "tinto"?
6. 🌟 Proyecto extra: Tabla del Intercolegiado
Situación
El comité deportivo necesita mostrar en consola la tabla de posiciones del torneo de microfútbol.
Requisitos
- Una lista de diccionarios con los equipos: nombre, partidos ganados (PG), empatados (PE) y perdidos (PP), goles a favor (GF) y goles en contra (GC).
- Calcular para cada equipo los puntos (3 por ganar, 1 por empatar) y la diferencia de gol (GF − GC).
- Construir un objeto
PrettyTableconfield_namesy agregar cada equipo conadd_rowdentro de unfor. - Ordenar por puntos, de mayor a menor, con los atributos
sortbyyreversesort. - Alinear a la izquierda la columna del nombre del equipo (
table.align["Equipo"] = "l").
Casos de prueba
Con 10A (3 PG, 1 PE, 0 PP) y 10B (2 PG, 2 PE, 0 PP): 10A tiene 10 puntos y aparece primero; 10B tiene 8.
⭐ Extensión
¿Qué pasa si dos equipos tienen los mismos puntos? Investiga si PrettyTable permite ordenar por varios criterios (puntos y luego diferencia de gol). Si no lo permite, ordena la lista tú mismo antes de construir la tabla.
7. 🏆 Proyecto integrador del Día 16: Panel de la Cafetería Escolar
Proyecto integrador creado para esta adaptación. Combina objetos de dos librerías distintas: el kit de la máquina de café (Anexo A) y PrettyTable. Esa es la gran ventaja de la POO: combinar piezas que otros construyeron.
Situación problema
El administrador de la cafetería quiere que la máquina muestre la información en tablas claras y lleve un historial de ventas.
Pregunta orientadora
¿Cómo lograr funcionalidades nuevas combinando objetos existentes, sin modificar su código?
Requerimientos
- No modificar
menu.py,coffee_maker.pynimoney_machine.py. Todo el trabajo va enmain.py. - Al iniciar, mostrar el menú como tabla (bebida, precio y los ingredientes: agua, leche y café), leyendo los atributos de los
MenuItem. (Pista:menu.menues la lista de objetos del kit.) reportmuestra los recursos y el dinero en una tabla. (Pista: el kit guarda los recursos encoffee_maker.resourcesy el dinero enmoney_machine.profit.)- Una lista
ventasen la que cada venta exitosa agregue un diccionario{"bebida": ..., "precio": ...}. - Una opción
ventasque muestre el historial en una tabla, con el total vendido y la bebida más vendida. - Corregir el problema del
None(bebida inexistente).
Reflexión obligatoria
Los puntos 2 y 3 leen atributos internos del kit (menu.menu, resources, profit) que no aparecen en la documentación de la interfaz. ¿Es buena idea depender de ellos? ¿Qué pasaría si el autor del kit los renombrara? (Este dilema se retoma en el Día 17, cuando crees tus propias clases.)
Entregables
main.pyfuncional.- Capturas de las tres tablas.
- Tabla de pruebas.
- El párrafo de reflexión.
Criterios técnicos
- Los archivos del kit quedan intactos: se puede comparar con el Anexo A.
- Ninguna entrada detiene el programa.
- El total de ventas coincide con
money_machine.profit.
8. 🤖 Programar con apoyo de IA
El proyecto de hoy enseña a confiar en una interfaz documentada sin leer el código interno. Una IA puede ayudarte a leer documentación más rápido, pero verifica lo que te diga contra la fuente.
Actividad: la IA y la documentación.
- Pregunta a una IA: "¿Cómo alineo a la izquierda una columna en PrettyTable?".
- Prueba su respuesta en Python y contrástala con la documentación de PyPI (se abre en otra pestaña).
- Pregúntale por un método de Turtle que no exista (por ejemplo
timmy.jump()). ¿Te dice que no existe o inventa una respuesta? Verifícalo en la documentación oficial.
9. 🛠️ Correcciones técnicas al material original
| Archivo | Afirmación o comportamiento del curso | Observación | Tratamiento |
|---|---|---|---|
113, 114 |
Código inicial de la máquina de café y su sitio de documentación | No están incluidos entre los materiales suministrados | Kit de reemplazo con la misma interfaz (Anexo A), probado |
114 |
drink = menu.find_drink(choice) sin verificar |
Con una bebida inexistente → AttributeError (verificado con el kit) |
Nota técnica y pruebas del proyecto |
114 |
Método "_resource_efficient" (error de dictado) |
El nombre correcto es is_resource_sufficient |
Tabla de la interfaz |
111 |
La documentación de PrettyTable está en Google Code Archive | Hoy está en PyPI y GitHub | Nota técnica del Tema 3 |
111 |
Ruta de instalación en PyCharm: "Preferences" | En Windows es File → Settings. Alternativa: pip install |
Tabla del Tema 3 |
112 |
print(table.align) muestra solo las columnas |
En PrettyTable 3.x aparece también base_align_value (verificado) |
Nota técnica del Tema 4 |
10. 📋 Matriz de trazabilidad
| Contenido original | Archivo de origen | Concepto desarrollado | Ejercicio original | Reto adicional | Proyecto relacionado |
|---|---|---|---|---|---|
| Por qué POO: espagueti, carro autónomo, restaurante | 108 |
Sección 0 | — | — | Secciones 5 y 7 |
| Clases, objetos, atributos, métodos (mesero) | 109 |
Tema 1 | — | Retos 1–4 del Tema 1 (diseño del Blackjack) | Todos |
| Construir objetos, PascalCase, notación de punto, Turtle, documentación | 110 |
Tema 2 | Timmy: forma, color, forward(100) |
Retos 1–4 del Tema 2 | Día 18 |
| Módulo frente a paquete, PyPI, instalación | 111 |
Tema 3 | Instalar PrettyTable | Reto 4 del Tema 4 | Secciones 6 y 7 |
PrettyTable: add_column, align |
112 |
Tema 4 | Tabla de Pokémon | Retos 1–4 del Tema 4 | Secciones 6 y 7 |
| Analogía del hotel, máquina de café con POO | 113 |
Sección 5 | Planteamiento del proyecto | — | Sección 5 |
Solución: objetos, get_items, find_drink, and |
114 |
Sección 5 | Proyecto oficial | Extensiones y corrección del None |
Secciones 5 y 7 |
| Repasar de vez en cuando | 115 |
Sección 0 | — | — | — |
| (No existe en el curso original) | — | — | — | Tabla del Intercolegiado | Sección 6 |
| (No existe en el curso original) | — | — | — | Panel de la Cafetería Escolar | Sección 7 |
| (No existe en el curso original) | — | — | — | Kit de reemplazo | Anexo A |
11. 📦 Evidencias de aprendizaje del Día 16
- Tabla de atributos y métodos de al menos dos objetos de la vida real (Tema 1).
- Captura de la tortuga Timmy (forma, color y movimiento).
- Tabla de Pokémon con PrettyTable, alineada a la izquierda.
- Máquina de Café con POO funcionando con el kit, incluida la corrección del
None. - Proyecto extra (Intercolegiado) o integrador (Panel de la Cafetería), con su reflexión.
- Vocabulario del día en tu cuaderno: clase, objeto, atributo, método, construir, PascalCase, paquete y PyPI, cada uno con un ejemplo propio.
12. 📎 Anexo A: Kit de reemplazo de la Máquina de Café
Creado para esta adaptación, porque el código inicial del curso no está incluido entre los materiales suministrados. Respeta la interfaz documentada por el curso (los mismos nombres de clases, atributos y métodos), usa pesos colombianos y los mensajes están en español. Se probó con las entradas de la tabla de pruebas de la Sección 5.
Para los estudiantes: igual que en el curso, no necesitas entender este código todavía. La sintaxis
class,__init__yselfse estudia en el Día 17. Hoy solo lo usas desdemain.py.
Crea estos tres archivos en la misma carpeta de tu main.py:
menu.py
class MenuItem:
"""Modela una bebida del menú."""
def __init__(self, name, water, milk, coffee, cost):
self.name = name
self.cost = cost
self.ingredients = {"water": water, "milk": milk, "coffee": coffee}
class Menu:
"""Modela el menú de bebidas."""
def __init__(self):
self.menu = [
MenuItem(name="latte", water=200, milk=150, coffee=24, cost=5000),
MenuItem(name="espresso", water=50, milk=0, coffee=18, cost=3000),
MenuItem(name="cappuccino", water=250, milk=100, coffee=24, cost=6000),
]
def get_items(self):
"""Devuelve los nombres de las bebidas disponibles, separados por /."""
options = ""
for item in self.menu:
options += f"{item.name}/"
return options
def find_drink(self, order_name):
"""Busca una bebida por su nombre. Devuelve el MenuItem, o None si no existe."""
for item in self.menu:
if item.name == order_name:
return item
print("Lo siento, esa bebida no está disponible.")
return Nonecoffee_maker.py
class CoffeeMaker:
"""Modela la máquina que prepara el café."""
NOMBRES = {"water": "agua", "milk": "leche", "coffee": "café"}
def __init__(self):
self.resources = {"water": 300, "milk": 200, "coffee": 100}
def report(self):
"""Imprime un informe de los recursos."""
print(f"Agua: {self.resources['water']} ml")
print(f"Leche: {self.resources['milk']} ml")
print(f"Café: {self.resources['coffee']} g")
def is_resource_sufficient(self, drink):
"""Devuelve True si se puede preparar la bebida, False si falta algún ingrediente."""
can_make = True
for item in drink.ingredients:
if drink.ingredients[item] > self.resources[item]:
print(f"Lo siento, no hay suficiente {self.NOMBRES[item]}.")
can_make = False
return can_make
def make_coffee(self, order):
"""Descuenta los ingredientes de los recursos."""
for item in order.ingredients:
self.resources[item] -= order.ingredients[item]
print(f"Aquí está tu {order.name} ☕. ¡Disfrútalo!")money_machine.py
class MoneyMachine:
"""Modela la máquina que recibe el dinero (pesos colombianos)."""
COINS = {"1000": 1000, "500": 500, "200": 200, "100": 100}
def __init__(self):
self.profit = 0
self.money_received = 0
def report(self):
"""Imprime las ganancias acumuladas."""
print(f"Dinero: ${self.profit}")
def process_coins(self):
"""Pide las monedas y devuelve el total insertado."""
print("Inserta monedas.")
for coin in self.COINS:
self.money_received += int(input(f"¿Cuántas monedas de ${coin}?: ")) * self.COINS[coin]
return self.money_received
def make_payment(self, cost):
"""Devuelve True si el pago es suficiente, False si no."""
self.process_coins()
if self.money_received >= cost:
change = self.money_received - cost
print(f"Tu cambio es ${change}.")
self.profit += cost
self.money_received = 0
return True
else:
print("Dinero insuficiente. Se te devuelve el dinero.")
self.money_received = 0
return False