Este tutorial adapta pedagógicamente el Día 9. Las secciones 📝 Ejercicio original del curso provienen de los archivos del curso. Los retos 🟢🟡🟠🔴, el proyecto extra y el proyecto integrador son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.
Tabla de contenidos
- Antes de empezar: la subasta a ciegas
- Diccionarios: claves y valores
- Anidamiento: listas y diccionarios dentro de otros
- 🚀 Proyecto del día: la Subasta Secreta
- 🌟 Proyecto extra: Inventario de la Biblioteca Escolar
- 🏆 Proyecto integrador del bloque "Principiante" (Días 1–9): Elecciones del Personero Estudiantil
- 🤖 Programar con apoyo de IA
- 🛠️ Correcciones técnicas al material original
- 📋 Matriz de trazabilidad
- 📦 Evidencias de aprendizaje del Día 9
0. Antes de empezar: la subasta a ciegas
(Fuente: 067 - Day 9 Goals- what we will make by the end of the day.md, 071 - Motivation and the Accountability Trick.md)
En una subasta tradicional todos ven las ofertas de los demás y las van subiendo. En una subasta a ciegas (o silenciosa), cada persona ofrece en secreto lo máximo que está dispuesta a pagar, y solo al final se revela quién ganó. Así funcionan, por ejemplo, muchas licitaciones del sector de la construcción y del gobierno.
Hoy programaremos esa subasta. Para guardar quién ofreció cuánto necesitamos una estructura nueva: el diccionario.
Truco de motivación del curso: busca a alguien (un familiar, un amigo o un compañero) que te pida cuentas cada semana: "¿Qué aprendiste? ¿Qué construiste?". Compártele tus proyectos, como el Ahorcado o la Isla del Tesoro.
Prerequisito general: listas y listas anidadas (Día 4), bucles (Días 5 y 6), funciones con parámetros (Día 8).
1. Diccionarios: claves y valores
(Fuente: 068 - The Python Dictionary- Deep Dive.md)
Prerequisito: listas e índices (Día 4).
🎯 Objetivo de aprendizaje
- Crear diccionarios y acceder a sus valores por clave.
- Agregar, editar y vaciar entradas.
- Recorrer un diccionario con
for.
🧠 ¿Qué aprenderemos?
- Pares clave: valor.
KeyError.- El diccionario vacío
{}. - El recorrido con
for clave in diccionario.
📖 Explicación conceptual
Un diccionario de Python funciona como un diccionario de la vida real: buscas una palabra (la clave) y obtienes su definición (el valor). Piénsalo como una tabla de dos columnas:
| Clave | Valor |
|---|---|
"Bug" |
"Un error en un programa que impide que se ejecute como se esperaba." |
"Function" |
"Un fragmento de código al que se puede llamar una y otra vez." |
programming_dictionary = {
"Bug": "Un error en un programa que impide que se ejecute como se esperaba.",
"Function": "Un fragmento de código al que se puede llamar una y otra vez.",
}- Llaves
{ }en lugar de corchetes. - Cada entrada es
clave: valor, y las entradas se separan con comas. - Convención de formato del curso: una entrada por línea, con sangría, y coma también después de la última. Así es más fácil agregar entradas nuevas.
Operaciones básicas
| Operación | Código | Resultado |
|---|---|---|
| Leer un valor | programming_dictionary["Bug"] |
La definición de Bug |
| Agregar | programming_dictionary["Loop"] = "Repetir una acción..." |
Una nueva entrada |
| Editar | programming_dictionary["Bug"] = "Una polilla en el computador." |
Se reemplaza el valor |
| Crear vacío | diccionario = {} |
Un diccionario sin entradas |
| Vaciar | programming_dictionary = {} |
Queda vacío (útil, por ejemplo, para reiniciar un juego) |
Agregar y editar usan la misma sintaxis. Si la clave existe, su valor se reemplaza; si no existe, se crea.
Diferencia con las listas
| Lista | Diccionario |
|---|---|
| Los elementos se identifican por su posición (0, 1, 2…) | Los elementos se identifican por su clave |
lista[0] |
diccionario["Bug"] |
Error por un índice inexistente: IndexError |
Error por una clave inexistente: KeyError |
Recorrer un diccionario. Una sorpresa frecuente: for recorre las claves, no los pares.
for clave in programming_dictionary:
print(clave) # la clave
print(programming_dictionary[clave]) # el valor, usando la clave🔎 Ejemplo explicado: notas de un curso
notas = {
"Sara": 4.5,
"Tomás": 3.2,
"Luisa": 2.8,
}
notas["Mateo"] = 4.0 # llega un estudiante nuevo
notas["Luisa"] = 3.1 # recuperó la materia
for estudiante in notas:
print(f"{estudiante}: {notas[estudiante]}")- Por qué usar un diccionario: cada nota queda asociada a un nombre. Con dos listas separadas sería fácil desalinear nombres y notas.
- Resultado esperado: cuatro líneas, en el orden en que se agregaron las entradas. Desde Python 3.7, los diccionarios conservan el orden de inserción.
⚠️ Errores frecuentes
1. KeyError por un error de tipeo
- Qué ocurre:
programming_dictionary["Bog"]produceKeyError: 'Bog'. - Cómo solucionarlo: revisa la ortografía y las mayúsculas:
"bug"y"Bug"son claves distintas.
2. Olvidar las comillas en las claves de texto
- Qué ocurre:
{Bug: "..."}produceNameError, porque Python cree queBuges una variable. - Cómo solucionarlo: si la clave es texto, va entre comillas. Si es un número, sin comillas:
{123: "..."}se lee condiccionario[123].
3. Esperar que el for entregue el valor
- Qué ocurre: solo se imprimen las claves.
- Cómo solucionarlo: usa
diccionario[clave], o investiga.items()como extensión.
📝 Ejercicio original del curso: ejercicio de codificación posterior
La lección remite a "un ejercicio de codificación" que pone a prueba los diccionarios. Su enunciado no está incluido entre los archivos suministrados. Los retos siguientes cubren el mismo objetivo.
Retos adicionales (creados para esta adaptación)
🟢 Reto 1: Aplicación
Crea un diccionario capitales con 5 departamentos de Colombia y sus capitales. Pide un departamento al usuario y muestra su capital.
🟡 Reto 2: Ampliación
Antes de buscar, verifica con if departamento in capitales: que la clave exista. Si no existe, muestra un mensaje en lugar del KeyError.
🟠 Reto 3: Desafío: conversor de notas
A partir de notas = {"Sara": 4.5, "Tomás": 3.2, ...}, construye con un for un nuevo diccionario desempeños que asigne a cada estudiante su desempeño ("Superior", "Alto", "Básico" o "Bajo", según la escala del Día 3).
🔴 Reto 4: Pensamiento computacional: contar palabras
Pide una frase y construye un diccionario que cuente cuántas veces aparece cada palabra. (Pista: frase.split() separa la frase en palabras. Para cada palabra, si ya es una clave suma 1; si no, créala con valor 1.)
🧩 Comprueba lo aprendido: Tema 1
- Conceptual: ¿cuándo conviene una lista y cuándo un diccionario? Da un ejemplo de cada caso.
- Predicción: ¿qué imprime este código?
d = {"a": 1, "b": 2}
d["a"] = 10
d["c"] = 3
print(d)
print(len(d))- Depuración: este código produce un error. Encuéntralo:
precios = {"empanada": 2500, "jugo": 3000}
print(precios["Empanada"])- Creación: crea un diccionario con tu horario (día → primera clase) y recórrelo para imprimirlo.
Evidencia: Reto 4 funcionando con una frase de al menos 10 palabras.
2. Anidamiento: listas y diccionarios dentro de otros
(Fuente: 069 - Nesting Lists and Dictionaries.md)
Prerequisito: Tema 1, listas anidadas (Día 4, Tema 3).
🎯 Objetivo de aprendizaje
- Guardar listas y diccionarios como valores dentro de otros diccionarios.
- Llegar a cualquier dato encadenando corchetes paso a paso.
📖 Explicación conceptual
¿Por qué anidar? Una clave solo puede tener un valor. Si quiero registrar varias ciudades visitadas de un país, "Francia": "París", "Lille" no funciona. La solución es que ese único valor sea una lista:
travel_log = {
"France": ["Paris", "Lille", "Dijon"],
"Germany": ["Stuttgart", "Berlin"],
}
print(travel_log["France"][1]) # LilleRecorrido paso a paso:
travel_log["France"]→["Paris", "Lille", "Dijon"], que es una lista.[1]sobre esa lista →"Lille".
Listas dentro de listas (repaso del Día 4):
nested_list = ["A", "B", ["C", "D"]]
print(nested_list[2][1]) # DDiccionarios dentro de diccionarios (varios niveles):
travel_log = {
"France": {
"num_times_visited": 8,
"cities_visited": ["Paris", "Lille", "Dijon"],
},
"Germany": {
"num_times_visited": 5,
"cities_visited": ["Berlin", "Hamburg", "Stuttgart"],
},
}
print(travel_log["Germany"]["cities_visited"][2]) # Stuttgart| Paso | Expresión | Resultado |
|---|---|---|
| 1 | travel_log["Germany"] |
Un diccionario con 2 claves |
| 2 | ...["cities_visited"] |
["Berlin", "Hamburg", "Stuttgart"] |
| 3 | ...[2] |
"Stuttgart" |
Estrategia del curso: avanza un corchete a la vez e imprime cada paso. Si una clave es larga, cópiala y pégala para evitar errores de tipeo.
⚠️ Errores frecuentes
- Usar un índice numérico en un diccionario:
travel_log[0]produceKeyError: 0. Los diccionarios no tienen posiciones: se accede por clave. - Usar una clave de texto en una lista:
travel_log["France"]["Paris"], cuando el valor es una lista, produceTypeError: list indices must be integers or slices, not str. - Perderse en el anidamiento: imprime el
type()del resultado en cada paso.
📝 Ejercicio original del curso: retos de acceso
- Imprime
"Lille"deltravel_logcon listas. - Imprime
"D"de["A", "B", ["C", "D"]]. - Imprime
"Stuttgart"deltravel_logcon diccionarios anidados.
La lección termina remitiendo a un cuestionario sobre diccionarios. Su contenido no está incluido entre los archivos suministrados.
Retos adicionales (creados para esta adaptación)
🟢 Reto 1: Aplicación
Del travel_log con diccionarios, imprime cuántas veces se visitó Francia.
🟡 Reto 2: Ampliación
Agrega al travel_log un país nuevo, con su número de visitas y sus ciudades, mediante código (no editando el diccionario original). Luego agrega una ciudad a Alemania con append().
🟠 Reto 3: Desafío
Recorre el travel_log e imprime, para cada país, "France: 8 visitas, 3 ciudades".
🔴 Reto 4: Pensamiento computacional: diseña la estructura
La coordinación necesita guardar, para cada curso (10A, 10B…), el director de grupo, la lista de estudiantes y el promedio del curso. Diseña la estructura de datos (¿diccionario de diccionarios? ¿lista de diccionarios?), escríbela con 2 cursos de ejemplo y escribe las expresiones para obtener: (a) el director de 10B, (b) el tercer estudiante de 10A, (c) el promedio de 10A. Justifica tu diseño.
🧩 Comprueba lo aprendido: Tema 2
- Predicción: con
d = {"x": [1, {"y": "¡hola!"}]}, ¿qué expresión imprime¡hola!? - Depuración:
print(travel_log["Germany"][2])produce un error con la versión de diccionarios anidados. ¿Qué error es y por qué? - Conceptual: ¿por qué
{"France": "Paris", "Lille"}no guarda dos ciudades?
3. 🚀 Proyecto del día: la Subasta Secreta
(Fuente: 070 - The Secret Auction Program Instructions and Flow Chart.md, proyecto oficial del curso original)
Problema
Construir un programa para una subasta a ciegas. Cada persona escribe su nombre y su oferta en el mismo computador, se "limpia" la pantalla para el siguiente participante y, al final, se anuncia el ganador.
Contexto
Sirve para subastar una obra de arte, para una rifa de curso o, como bromea el curso, para decidir entre hermanos quién usa primero el trampolín.
Requisitos funcionales
- Mostrar el logo de la subasta (arte ASCII).
- Pedir nombre y oferta.
- Guardar cada oferta en un diccionario:
{nombre: oferta}. - Preguntar "¿Hay otros oferentes? (si/no)".
- Si la respuesta es sí: limpiar la pantalla y pedir la siguiente oferta.
- Si es no: encontrar la oferta más alta y anunciar
El ganador es Jenny con una oferta de $121.
Restricciones técnicas
Diccionario, while, una función con parámetro para encontrar al ganador, for sobre el diccionario y f-strings. Para "limpiar" la pantalla, el curso propone simplemente imprimir muchos saltos de línea: print("\n" * 100).
🔍 Antes de programar: diagrama de flujo
El curso recomienda dibujar tu propio diagrama antes de ver el suyo. Este es el del curso:
flowchart TD
A([Mostrar logo]) --> B[/Pedir nombre/]
B --> C[/Pedir oferta/]
C --> D[Agregar nombre: oferta al diccionario]
D --> E{¿Hay más oferentes?}
E -- Sí --> F[Limpiar pantalla] --> B
E -- No --> G[Recorrer el diccionario y encontrar la oferta más alta]
G --> H([Anunciar ganador])Preguntas de diseño:
- ¿El diccionario de ofertas se crea dentro o fuera del
while? (Recuerda la listacorrect_lettersdel Día 7.) - ¿Qué tipo de dato debe tener la oferta? ¿
intofloat? - ¿Por qué conviene poner la búsqueda del ganador en una función? (Según el curso: funcionalidad separada y reutilizable, y un código principal más limpio.)
Construcción paso a paso (siguiendo la solución del curso)
Versión 1: una oferta. Pedir el nombre y la oferta (convertida con int() o float()) y guardarla: bids[name] = price.
Versión 2: varias ofertas. Un while controlado por la bandera continue_bidding. Al final de cada vuelta, preguntar si hay más oferentes. Usa .lower() para aceptar "SI", "Si" o "si".
Versión 3: el ganador. La función find_highest_bidder(bidding_dictionary):
- Recorre las claves (los nombres).
- Obtiene cada oferta con
bidding_dictionary[bidder]. - Usa el patrón de "máximo" del Día 5:
highest_bid, que empieza en 0, ywinner, que se actualizan juntos. - Recuerda: la función debe definirse antes de llamarla (Día 6).
Versión 4: logo y limpieza de pantalla. import art y print(art.logo). El archivo art.py del curso no está incluido entre los materiales suministrados: crea tu propio logo.
Alternativa mencionada por el curso
max(bids, key=bids.get)Esta línea devuelve la clave con el valor más alto. El curso la menciona, pero recomienda que, mientras aprendes, resuelvas el problema desde los primeros principios (con el bucle): "en el futuro será mucho más fácil de entender que un código que sacaste de internet".
Pruebas
| Ofertas | Ganador esperado |
|---|---|
| Angela 12, John 3, Kate 1 | Angela, $12 |
| Ana 5, Luis 5 (empate) | Ana, porque llegó primero. ¿Es justo? |
| Ana 10, luego Ana 4 | ⚠️ Con el diccionario, la segunda oferta reemplaza a la primera: {"Ana": 4} |
| Ana 0 (única oferta) | ⚠️ La solución del curso falla con UnboundLocalError |
| "cien" como oferta | ⚠️ ValueError |
🛠️ Nota técnica: los casos marcados con ⚠️ se verificaron ejecutando la solución del curso.
- Nombre repetido: las claves de un diccionario son únicas, así que la nueva oferta sobrescribe la anterior. Decide si eso es lo correcto o si debes impedirlo con
if name in bids:.- Oferta de 0: como
highest_bidempieza en 0 y la condición es>,winnernunca se asigna. Solución: inicializarwinner = ""o comparar con>=, pensando en qué pasa con los empates.- Entrada no numérica: en el Día 9 todavía no sabemos manejar excepciones. Por ahora, deja un mensaje claro en la pregunta. El manejo de errores (
try/except) llega más adelante en el curso.
🧪 Prueba y depuración
Este código tiene cuatro errores. Encuéntralos:
continue_bidding = True
while continue_bidding:
bids = {}
name = input("¿Cuál es tu nombre?: ")
price = input("¿Cuál es tu oferta?: $")
bids[name] = price
should_continue = input("¿Hay otros oferentes? si/no\n")
if should_continue == "no":
continue_bidding = False
find_highest_bidder(bids)
elif should_continue == "si":
print("\n" * 100)
def find_highest_bidder(bidding_dictionary):
...(Pistas: un diccionario que se reinicia, una oferta que se queda como texto, una función definida demasiado tarde y un .lower() que falta.)
⭐ Extensión del proyecto
- Mostrar al final todas las ofertas ordenadas de mayor a menor.
- Anunciar un empate si dos o más personas ofrecen el mismo máximo.
- Limpiar la pantalla de verdad: investiga
os.system("cls")(Windows) yos.system("clear")(Mac y Linux). - Rechazar ofertas menores que un precio base definido al inicio.
4. 🌟 Proyecto extra: Inventario de la Biblioteca Escolar
Situación
La biblioteca del colegio lleva el inventario en un cuaderno. Necesita un programa que registre los libros y sus préstamos.
Estructura de datos (diccionario de diccionarios)
biblioteca = {
"Cien años de soledad": {"autor": "Gabriel García Márquez", "copias": 3, "prestados": 1},
"María": {"autor": "Jorge Isaacs", "copias": 2, "prestados": 0},
}Requisitos
- Un menú repetitivo (
while) con estas opciones: ver inventario, prestar, devolver, agregar libro y salir. - Una función con parámetros por cada acción. Por ejemplo,
prestar(inventario, titulo). - Prestar: solo si el título existe (
in) y hay copias disponibles (copias - prestados > 0). - Devolver: solo si hay al menos un ejemplar prestado.
- Ver inventario: recorrer el diccionario y mostrar el título, el autor y las copias disponibles.
Casos de prueba
| Acción | Resultado esperado |
|---|---|
| Prestar "María" 3 veces (tiene 2 copias) | Las dos primeras funcionan; la tercera dice "No hay copias disponibles" |
| Prestar "Harry Potter" (no existe) | "El libro no está en el inventario" (sin KeyError) |
| Devolver "María" con 0 prestados | "No hay préstamos de este libro" |
⭐ Extensión
Guarda también quién tiene cada préstamo, con una lista de nombres dentro de cada libro.
5. 🏆 Proyecto integrador: Elecciones del Personero Estudiantil
Proyecto integrador creado para esta adaptación. Con el Día 9 termina la primera parte del curso (nivel principiante; el Día 10 abre las funciones con salidas). Este proyecto integra los conceptos de los Días 1 a 9.
Situación problema
Cada año los colegios de Colombia eligen al personero estudiantil mediante votación. Tu reto es programar una urna electoral de consola que garantice el voto secreto, evite votos duplicados y produzca resultados confiables.
Pregunta orientadora
¿Cómo diseñar un programa que maneje datos estructurados, valide cada entrada y dé resultados que toda la comunidad educativa pueda confiar?
Requerimientos
| # | Requerimiento | Conceptos (día) |
|---|---|---|
| 1 | Logo e instrucciones en un módulo aparte | print, módulos (1, 4, 7) |
| 2 | Diccionario de candidatos: {número: {"nombre": ..., "votos": 0}}, incluido el voto en blanco |
Diccionarios anidados (9) |
| 3 | Lista de documentos de identidad habilitados para votar | Listas (4) |
| 4 | Bucle de votación hasta que el jurado escriba una clave de cierre | while, bandera (6, 7) |
| 5 | Validar que el documento esté habilitado y que no haya votado ya | in, and/not (3, 7) |
| 6 | Mostrar el tarjetón con un for y validar el número elegido |
for, int(), validación (2, 5) |
| 7 | "Limpiar" la pantalla después de cada voto | "\n" * 100 (9) |
| 8 | Funciones con parámetros: mostrar_tarjeton(candidatos), registrar_voto(candidatos, numero), mostrar_resultados(candidatos, total_votantes) |
Funciones (6, 8) |
| 9 | Resultados: votos y porcentaje con un decimal por candidato, participación y ganador | Operaciones, round, f-strings (2) |
| 10 | Manejo de empate en el primer lugar | Condicionales, acumuladores (3, 5) |
Restricciones técnicas
Solo conceptos de los Días 1 a 9. Sin return (Día 10): las funciones modifican el diccionario que reciben o imprimen información. (Investiga por qué una función puede modificar un diccionario que recibe como parámetro, pero no un número.)
Etapas de desarrollo
- Diseño: diagrama de flujo y estructura de datos, en papel.
- Tarjetón y registro de un voto.
- Bucle de votación con cierre.
- Validaciones de documento y de voto duplicado.
- Resultados, porcentajes y empate.
- Pruebas y depuración.
Entregables
- Código en al menos 2 archivos.
- Diagrama de flujo.
- Tabla de pruebas con los resultados.
- Registro de errores y soluciones.
- Demostración en vivo ante el grupo.
Casos de prueba mínimos
| Situación | Resultado esperado |
|---|---|
| Documento no habilitado | "No está habilitado para votar" y no se registra ningún voto |
| El mismo documento vota dos veces | El segundo voto se rechaza |
| Número de candidato inexistente | Se vuelve a pedir el número y no se registra nada |
| 3 votos para el candidato 1, 1 para el 2 y 1 en blanco | 60.0 %, 20.0 %, 20.0 % |
| 2 y 2 votos entre dos candidatos | Se anuncia el empate |
| Cierre sin ningún voto | Mensaje de "sin votos" y ninguna división por cero |
Criterios técnicos de funcionamiento
- El programa no se detiene por errores con ninguna entrada de la tabla de pruebas.
- La suma de los votos es igual al número de votantes registrados.
- El código es legible: funciones con nombres claros, estructura de datos documentada con comentarios y sangría consistente.
Posibles extensiones
- Elegir también al contralor estudiantil en la misma jornada (dos diccionarios de candidatos).
- Resultados por curso (anidamiento adicional).
- Gráfico de barras en la consola con
*.
6. 🤖 Programar con apoyo de IA
El curso muestra max(bids, key=bids.get), una solución de una línea que "se encuentra en internet", pero recomienda entender primero la versión con el bucle. Con la IA pasa lo mismo: puede darte código muy compacto que no entiendes.
Actividad: explicar antes de usar.
- Pide a una IA la función que encuentra al ganador de la subasta.
- Si usa algo que no conoces (
max(..., key=...),sorted,lambda,.items()), no lo pegues todavía. Pídele que te lo explique paso a paso, verifica la explicación en la documentación oficial (se abre en otra pestaña) y reescríbelo con tus palabras en un comentario. - Pasa su código por la tabla de pruebas del proyecto. ¿Maneja el empate? ¿Y la oferta de 0?
7. 🛠️ Correcciones técnicas al material original
| Archivo | Comportamiento del curso | Observación (verificada) | Tratamiento |
|---|---|---|---|
070 |
highest_bid = 0 con la condición > |
Si todas las ofertas son 0, winner no se asigna y se produce UnboundLocalError |
Nota técnica y pruebas del proyecto |
070 |
bids[name] = price |
Un nombre repetido sobrescribe la oferta anterior | Nota técnica y pruebas |
070 |
Oferta convertida con int(input()) |
Una entrada no numérica produce ValueError (las excepciones se ven más adelante en el curso) |
Nota técnica |
070 |
Limpiar la pantalla con "\n" * 100 |
Funciona, pero se puede ver lo anterior desplazándose hacia arriba | Extensión: os.system |
068 |
"Vaciar" con diccionario = {} |
Crea un diccionario nuevo; .clear() vacía el mismo objeto. La diferencia importa cuando otras variables apuntan a él |
Mención en el integrador (paso de diccionarios a funciones) |
068, 069 |
Ejercicio de codificación y cuestionario | No están incluidos entre los archivos suministrados | Retos equivalentes |
8. 📋 Matriz de trazabilidad
| Contenido original | Archivo de origen | Concepto desarrollado | Ejercicio original | Reto adicional | Proyecto relacionado |
|---|---|---|---|---|---|
| Objetivos: subasta silenciosa | 067 |
Sección 0 | — | — | Sección 3 |
Diccionarios: crear, leer, agregar, editar, vaciar, recorrer, KeyError |
068 |
Tema 1 | Ejercicio posterior (mencionado, no suministrado) | Retos 1–4 del Tema 1 (contar palabras) | Secciones 3, 4 y 5 |
| Anidamiento: listas y diccionarios dentro de diccionarios, listas 2D | 069 |
Tema 2 | Acceder a Lille, D y Stuttgart. Cuestionario (mencionado, no suministrado) | Retos 1–4 del Tema 2 (estructura de cursos) | Secciones 4 y 5 |
Subasta secreta: diagrama, diccionario, while, función, max |
070 |
Integración | Proyecto oficial completo | Depuración con 4 errores, casos límite y extensiones | Sección 3 |
| Motivación: alguien que te pida cuentas | 071 |
Sección 0 | — | — | — |
| (No existe en el curso original) | — | — | — | Inventario de la Biblioteca | Sección 4 |
| (No existe en el curso original) | — | — | — | Elecciones del Personero (integra los Días 1–9) | Sección 5 |
9. 📦 Evidencias de aprendizaje del Día 9
- Subasta Secreta funcionando, con la tabla de pruebas y los casos límite analizados.
- Diagrama de flujo propio de la subasta.
- Retos de acceso anidado resueltos (Lille, D, Stuttgart) y la estructura de datos del Reto 4 del Tema 2.
- Proyecto extra (Biblioteca) o integrador (Personero).
- Cuaderno de errores:
KeyError,TypeError: list indices must be integers,UnboundLocalErroren la subasta y el diccionario reiniciado dentro delwhile.