Saltar al contenido
Inicio 100 Días de Código en Python — Día 26: Comprensión de Listas y el Alfabeto Fonético de la OTAN

100 Días de Código en Python — Día 26: Comprensión de Listas y el Alfabeto Fonético de la OTAN

Nivel: Grado décimo Área: Tecnología e Informática Modalidad: Tutorial práctico Fuente: Curso "100 Days of Code: The Complete Python Pro Bootcamp" (Angela Yu, App Brewery). Contenido del Día 26 (nivel intermedio).

Este tutorial adapta pedagógicamente el Día 26. Las secciones 📝 Ejercicio original del curso provienen de los archivos del curso. Los retos 🟢🟡🟠🔴 y el proyecto extra son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.

Nota sobre las verificaciones: los ejemplos se ejecutaron con Python 3.14 y pandas 3.0.6. El archivo nato_phonetic_alphabet.csv del curso no está en la carpeta; se usó una versión reducida con las columnas letter y code, que son las que nombra la lección 202. Los puntajes aleatorios de la lección 199 cambian en cada ejecución, así que los tuyos no coincidirán con los de este tutorial.

Nota sobre los ejercicios de práctica: la lección 197 menciona una serie de ejercicios de código ("flexiones de código") sobre comprensiones. Esos ejercicios no están en la carpeta, así que no se reproducen aquí. En su lugar, cada tema incluye retos creados para esta adaptación.


Tabla de contenidos

  1. Antes de empezar
  2. Comprensión de listas
  3. Comprensión de listas condicional
  4. Aplicarlo al juego de los estados
  5. Comprensión de diccionarios
  6. Recorrer un DataFrame de pandas con iterrows
  7. 🚀 Proyecto del día: el deletreador con el alfabeto de la OTAN
  8. 🌟 Proyecto extra: el codificador Morse de la emisora escolar
  9. 🧩 Comprueba lo aprendido
  10. 🤖 Programar con apoyo de IA
  11. 🛠️ Correcciones técnicas al material original
  12. 📋 Matriz de trazabilidad
  13. 📦 Evidencias de aprendizaje del Día 26

0. Antes de empezar

(Fuente: 196 - Day 26 Goals- what you will make by the end of the day.md)

Hoy aprenderemos las comprensiones de listas y de diccionarios. El curso las presenta como una característica muy propia de Python que reduce mucho el código cuando trabajamos con listas y diccionarios.

El proyecto del día surge de un problema real: cuando deletreas tu nombre por teléfono, la otra persona puede confundir letras que suenan parecido (¿dijiste B o V? ¿M o N?). El alfabeto fonético de la OTAN asigna una palabra a cada letra: A de Alfa, N de November, G de Golf… Construiremos un programa de consola que recibe una palabra y devuelve la lista de palabras clave para deletrearla.

💡 Para pensar: ¿dónde has tenido que deletrear algo? En una llamada al banco, al dictar tu correo electrónico, al dar el número de una placa… En Colombia es común decir "B de burro" o "V de vaca". El alfabeto OTAN es la versión estandarizada internacionalmente.

Prerequisito general: listas y append (Día 4), bucles for y range (Día 5), diccionarios y .items() (Día 9), métodos de strings como .upper() (Día 8), random.randint (Día 4), pandas, read_csv y DataFrames (Día 25) y el juego de los estados (Día 25).


1. Comprensión de listas

(Fuente: 197 - How to Create Lists using List Comprehension.md)

🎯 Objetivo de aprendizaje

  • Crear una lista nueva a partir de otra secuencia en una sola línea.
  • Leer una comprensión de listas usando el patrón de palabras clave del curso.

🧠 ¿Qué aprenderemos?

Una comprensión de listas (list comprehension) es una forma corta de crear una lista nueva a partir de otra secuencia. Hasta hoy lo hacíamos con un bucle for y append.

📖 Explicación conceptual

El problema: tenemos [1, 2, 3] y queremos una lista con cada número aumentado en 1.

Con lo que ya sabemos (4 líneas):

Python
numbers = [1, 2, 3]
new_list = []
for n in numbers:
    add_1 = n + 1
    new_list.append(add_1)
# new_list → [2, 3, 4]

Con una comprensión (1 línea):

Python
new_numbers = [n + 1 for n in numbers]   # [2, 3, 4]  (verificado)

El método de palabras clave del curso. Angela recomienda escribir primero el patrón con palabras genéricas y luego reemplazarlas una por una:

Texto
new_list = [new_item for item in list]
Palabra clave ¿Qué es? En el ejemplo
list La secuencia que vamos a recorrer numbers
item El nombre que le damos a cada elemento (cualquiera, pero úsalo igual en todo el patrón) n
new_item La expresión que calcula cada elemento de la lista nueva n + 1

Orden de lectura sugerido: empieza por la parte de la derecha ("para cada n en numbers") y termina por la izquierda ("agrega n + 1").

No solo con listas. El nombre dice "listas", pero funciona con cualquier secuencia: strings, range, tuplas… El curso lo explica así: estas estructuras tienen un orden, y la comprensión las recorre en ese orden.

💡 Consejo del curso: para practicar, usa la consola de Python de PyCharm en lugar de main.py. Ahí escribes línea por línea y ves el valor de cada variable en el panel de la derecha. El curso incluso muestra cómo corregir un valor desde ese panel (clic derecho → Set Value).

📝 Ejercicio original del curso 1: las letras de un nombre

Enunciado: con name = "Angela", ¿qué contendrá esta lista? Piensa la respuesta antes de ejecutarla.

Python
name = "Angela"
letters_list = [letter for letter in name]

Ver resultado

['A', 'n', 'g', 'e', 'l', 'a'] (verificado). El new_item es la misma letra, sin modificar: la comprensión simplemente separa el string en letras.

📝 Ejercicio original del curso 2: duplicar un rango

Enunciado: usando range(1, 5), crea range_list en la que cada número esté multiplicado por 2. El resultado debe ser [2, 4, 6, 8].

Pista del curso: recuerda que range(1, 5) va de 1 a 4; el 5 no se incluye.

🔍 Antes de programar

  • ¿Cuál es la list en este caso? (Pista: no es una lista.)
  • ¿Qué nombre le darás a cada item?
  • ¿Qué expresión produce cada new_item?

⚠️ Errores frecuentes

Error Qué ocurre Solución
Usar paréntesis: (n + 1 for n in numbers) No obtienes una lista, sino un "generador" que se imprime como <generator object ...> Las comprensiones de listas van entre corchetes [ ]
Nombres distintos: [num + 1 for n in numbers] NameError: name 'num' is not defined Usa el mismo nombre en new_item y en item
Olvidar asignar el resultado: [n + 1 for n in numbers] sola en un archivo La lista se crea y se pierde Guárdala en una variable: new_numbers = [...]
Pensar que range(1, 5) incluye el 5 Resultado con un elemento de menos o de más El final de range no se incluye

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1 — Aplicación: con temperaturas_c = [12, 18, 25, 31], crea temperaturas_f convirtiendo cada valor a Fahrenheit (c * 9 / 5 + 32).
  • 🟡 Reto 2 — Ampliación: con frase = "Python es genial", crea una lista con la longitud de cada palabra. (Pista: primero convierte la frase en una lista de palabras con un método de strings que ya conoces.)
  • 🟠 Reto 3 — Desafío: con notas = ["4.5", "3.2", "2.8"] (strings, como si vinieran de un archivo), crea una lista de números decimales y calcula el promedio en la línea siguiente.
  • 🔴 Reto 4 — Pensamiento computacional: tienes una lista con los nombres de los estudiantes del curso, escritos de cualquier manera (" ana maría ", "CARLOS", "luisa"). Diseña una comprensión que los deje todos limpios y con mayúscula inicial. Luego explica: ¿qué pasa con un nombre como "maría josé de la hoz" si usas .title()? ¿Es un resultado aceptable?

2. Comprensión de listas condicional

(Fuente: 197 - How to Create Lists using List Comprehension.md, segunda parte)

🎯 Objetivo de aprendizaje

  • Filtrar elementos de una secuencia dentro de una comprensión.
  • Combinar filtro y transformación en la misma línea.

📖 Explicación conceptual

El patrón se amplía con dos palabras clave más: if y una prueba (test).

Texto
new_list = [new_item for item in list if test]

El new_item solo se agrega si la prueba da True.

Ejemplo del curso: nombres cortos (4 letras o menos).

Python
names = ["Alex", "Beth", "Caroline", "Dave", "Eleanor", "Freddie"]
short_names = [name for name in names if len(name) < 5]
# ['Alex', 'Beth', 'Dave']  (verificado)

Cómo se ejecuta: Python recorre cada name; revisa si len(name) < 5; si se cumple, agrega name (sin modificar) a la lista nueva.

Detalle del curso: en la lista original había un error de escritura, "Elanor", y Angela lo corrige desde el panel de variables de la consola. El nombre correcto es "Eleanor".

📝 Ejercicio original del curso: nombres largos en mayúsculas

Enunciado: con la misma lista names, crea long_names con los nombres de 5 letras o más, convertidos a mayúsculas. Resultado esperado: ['CAROLINE', 'ELEANOR', 'FREDDIE'].

🔍 Antes de programar

  • ¿Qué parte del patrón hace el filtro? ¿Qué parte hace la transformación?
  • "5 letras o más" se escribe len(name) >= 5 o len(name) > 4. ¿Da lo mismo len(name) > 5? (Ver la nota técnica.)

🛠️ Nota técnica: en la solución del curso la prueba es len(name) > 5, aunque el enunciado dice "5 letras o más". Con esta lista el resultado es el mismo, porque ningún nombre tiene exactamente 5 letras. Pero si agregas "Bruno" a la lista, > 5 lo deja por fuera y >= 5 lo incluye. Lección: prueba siempre los casos límite.

⚠️ Errores frecuentes

Error Qué ocurre Solución
Poner el if antes del for: [name if len(name) < 5 for name in names] SyntaxError Para filtrar, el if va al final
Confundir < con <= Se pierden o sobran los casos límite Escribe un caso de prueba con el valor exacto del límite
Transformar en la prueba: if len(name.upper()) > 5 esperando mayúsculas La lista sale sin cambios La transformación va en new_item, la prueba solo decide si entra

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: con numeros = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55], crea una lista solo con los pares.
  • 🟡 Reto 2: con una lista de correos ["ana@colegio.edu.co", "luis@gmail.com", "sofi@colegio.edu.co"], obtén solo el usuario (lo que va antes de @) de los correos institucionales.
  • 🟠 Reto 3: con notas = {"Ana": 4.2, "Luis": 2.9, "Sofía": 3.0}, crea una lista con los nombres de quienes aprobaron (nota ≥ 3.0). (Pista: puedes recorrer notas.items().)
  • 🔴 Reto 4 — Pensamiento computacional: dos listas, inscritos_futbol e inscritos_robotica. Con una comprensión, obtén quiénes están en ambos clubes. Luego obtén quiénes están solo en robótica. ¿Qué pasa si un nombre está escrito con mayúscula en una lista y en minúscula en la otra? Propón una solución.

3. Aplicarlo al juego de los estados

(Fuente: 198 - Apply List Comprehension to the U.S. States Game.md)

📝 Ejercicio original del curso

Enunciado: abre tu juego de los estados de EE. UU. (Día 25). En la parte donde el usuario escribe exit, reemplaza el bucle que construye missing_states por una comprensión de listas y reduce el código en 3 o 4 líneas.

El código del Día 25:

Python
missing_states = []
for state in all_states:
    if state not in guessed_states:
        missing_states.append(state)

🔍 Antes de programar

  • ¿Cuál es la list? ¿Cuál es el item?
  • ¿Cuál es la prueba?
  • ¿El new_item se modifica o queda igual?

Solución del curso (en palabras): la lista es all_states, cada elemento es un state, la prueba es state not in guessed_states y el nuevo elemento es el mismo state.

Reflexión del curso: la línea nueva no solo es más corta, también se lee casi como una frase: "agrega cada estado de todos los estados si no está entre los adivinados".

💡 Conexión: en el tutorial del Día 25 se anunció esta mejora. Si hiciste el proyecto extra de los departamentos de Colombia, aplica el mismo cambio allí.

Reto adicional (creado para esta adaptación)

  • 🟠 Reto: en el mismo juego, reescribe con comprensiones otras dos partes del código que usen un bucle para construir una lista. Si no encuentras ninguna, escribe una comprensión que produzca la lista de estados adivinados que empiezan por "New".

4. Comprensión de diccionarios

(Fuente: 199 - How to use Dictionary Comprehension.md)

🎯 Objetivo de aprendizaje

  • Crear un diccionario a partir de una lista.
  • Crear un diccionario filtrando otro diccionario.

📖 Explicación conceptual

La idea es la misma, pero ahora se crea un diccionario. Por eso se usan llaves { } y cada elemento es un par clave: valor.

Patrón 1 — desde una lista (o cualquier iterable):

Texto
new_dict = {new_key: new_value for item in list}

Patrón 2 — desde otro diccionario:

Texto
new_dict = {new_key: new_value for (key, value) in dict.items()}

Patrón 3 — con condición:

Texto
new_dict = {new_key: new_value for (key, value) in dict.items() if test}

Recuerda (Día 9): .items() es un método: lleva paréntesis. Devuelve cada par clave-valor para que lo separemos en key y value.

📝 Ejercicio original del curso 1: puntajes aleatorios

Enunciado: a partir de la lista de nombres, crea students_scores, un diccionario en el que cada estudiante tenga un puntaje aleatorio entre 1 y 100.

Python
import random

names = ["Alex", "Beth", "Caroline", "Dave", "Eleanor", "Freddie"]
students_scores = {student: random.randint(1, 100) for student in names}
# Ejemplo de una ejecución: {'Alex': 18, 'Beth': 73, 'Caroline': 98, ...}

Comentario del curso (con humor): "Profesores, espero que esta no sea la forma en que ponen las notas".

📝 Ejercicio original del curso 2: estudiantes que aprobaron

Enunciado: a partir de students_scores, crea passed_students con los estudiantes que obtuvieron 60 o más, conservando su puntaje.

🔍 Antes de programar

  • ¿Por qué aquí se usa .items() y en el ejercicio anterior no?
  • ¿Qué nombres vas a dar a la clave y al valor? (El curso usa student y score.)
  • ¿La clave y el valor del diccionario nuevo cambian, o son los mismos?

Solución del curso (en palabras): recorrer students_scores.items() separando (student, score), conservar student: score y agregar la prueba if score >= 60.

⚠️ Errores frecuentes

Error Qué ocurre Solución
Olvidar los paréntesis: students_scores.items TypeError: 'builtin_function_or_method' object is not iterable .items()
Recorrer el diccionario sin .items() y pedir dos variables ValueError: too many values to unpack (o recorre solo las claves) Usa for (key, value) in dict.items()
Usar corchetes en lugar de llaves Se crea una lista, no un diccionario Diccionario → { }
Olvidar import random NameError: name 'random' is not defined Importa el módulo al inicio

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: con palabras = ["sol", "montaña", "río"], crea un diccionario {palabra: cantidad_de_letras}.
  • 🟡 Reto 2: con precios_usd = {"cuaderno": 2.5, "lápiz": 0.4, "calculadora": 12}, crea precios_cop convirtiendo a pesos colombianos. Consulta la tasa de cambio del día en una fuente confiable y cítala.
  • 🟠 Reto 3: con temperaturas = {"lunes": 12, "martes": 14, ..., "domingo": 24} (en °C), crea en una línea un diccionario con los días de más de 20 °C, con la temperatura ya convertida a °F.
  • 🔴 Reto 4 — Pensamiento computacional: tienes codigos = {"A": "Alfa", "B": "Bravo", ...}. Con una comprensión, crea el diccionario invertido ({"Alfa": "A", ...}). ¿Qué pasaría si dos claves tuvieran el mismo valor? Pruébalo y explica qué información se pierde.

5. Recorrer un DataFrame de pandas con iterrows

(Fuente: 200 - How to Iterate over a Pandas DataFrame.md)

🎯 Objetivo de aprendizaje

  • Diferenciar recorrer las columnas de un DataFrame y recorrer sus filas.
  • Usar iterrows() para acceder a los datos de cada fila.

📖 Explicación conceptual

Partimos de un diccionario que ya conoces:

Python
student_dict = {
    "student": ["Angela", "James", "Lily"],
    "score": [56, 76, 98],
}

Recorrer un diccionario: for (key, value) in student_dict.items(): da las claves (student, score) y sus listas.

Un DataFrame se puede recorrer igual, porque en muchos aspectos se comporta como un diccionario:

Python
import pandas

student_data_frame = pandas.DataFrame(student_dict)

for (key, value) in student_data_frame.items():
    print(key)          # student, score  → ¡los NOMBRES DE LAS COLUMNAS!

El curso señala que esto no es muy útil: recorre las columnas, y casi siempre queremos recorrer las filas. Para eso pandas tiene iterrows():

Python
for (index, row) in student_data_frame.iterrows():
    print(index)        # 0, 1, 2
    print(row.student)  # Angela, James, Lily
    print(row.score)    # 56, 76, 98
  • index es el número de la fila (la primera columna que muestra pandas).
  • row es una Series de pandas (Día 25), así que puedes leer cada columna con notación de punto: row.student, row.score.

Ejemplo del curso: buscar el puntaje de Angela.

Python
for (index, row) in student_data_frame.iterrows():
    if row.student == "Angela":
        print(row.score)    # 56  (verificado)

Recuerda (Día 25): la notación de punto no sirve si el nombre de la columna tiene espacios. En ese caso usa row["nombre con espacios"].

Retos adicionales (creados para esta adaptación)

  • 🟢 Reto 1: con student_data_frame, imprime una frase por estudiante: "Lily obtuvo 98".
  • 🟡 Reto 2: imprime solo los estudiantes con puntaje mayor que el promedio (calcula el promedio con un método de pandas del Día 25).
  • 🟠 Reto 3: resuelve el Reto 2 sin iterrows, filtrando el DataFrame como en el Día 25. ¿Cuál solución te parece más clara? ¿Cuál escribirías si el archivo tuviera un millón de filas? (Ver la nota técnica de la sección 6.)
  • 🔴 Reto 4: carga tu mi_semana.csv del Día 25 y, con iterrows, construye un diccionario {dia: condicion}. Luego busca cómo hacerlo sin iterrows.

6. 🚀 Proyecto del día: el deletreador con el alfabeto de la OTAN

(Fuentes: 201 - Introducing the NATO Alphabet Project.md, 202 - Solution & Walkthrough for the NATO Alphabet Project.md)

Problema

Construir un programa de consola que pida una palabra y muestre la lista de palabras del alfabeto fonético de la OTAN que corresponden a cada letra.

Contexto

La anécdota del curso: al deletrear por teléfono, Angela a veces olvida el código y termina inventando cosas como "P de pneumonia" o "M de mnemonic", que empiezan con letras mudas y no sirven de nada. El alfabeto OTAN existe justamente para que nadie confunda una E con una B o una T con una C.

Archivos del proyecto inicial (según la lección 202)

Archivo Contenido
nato_phonetic_alphabet.csv Columnas letter y code: cada letra y su palabra clave
main.py Los ejemplos de recorrido de la lección 200 (diccionario y DataFrame)

Requisitos funcionales

  1. Paso 1 (el más difícil, según el curso): convertir el CSV en un diccionario con este formato: {"A": "Alfa", "B": "Bravo", ...}.
  2. Paso 2: pedir una palabra y mostrar la lista de códigos, por ejemplo THOMAS → ['Tango', 'Hotel', 'Oscar', 'Mike', 'Alfa', 'Sierra'].
  3. Aceptar la palabra en mayúsculas o minúsculas.

Restricciones técnicas

  • Paso 1 con una comprensión de diccionario y iterrows().
  • Paso 2 con una comprensión de listas.

Planificación

  1. Entradas: el CSV y la palabra del usuario.
  2. Procesos: construir el diccionario; convertir la palabra a mayúsculas; buscar cada letra.
  3. Salida: una lista de palabras clave.
  4. Pregunta clave: ¿por qué no basta con data.to_dict()?

Construcción paso a paso

Versión 1 — Leer el CSV y ver por qué to_dict() no sirve.

Python
import pandas

data = pandas.read_csv("nato_phonetic_alphabet.csv")
print(data.to_dict())

Resultado verificado con los datos de prueba:

Texto
{'letter': {0: 'A', 1: 'B'}, 'code': {0: 'Alfa', 1: 'Bravo'}}

to_dict() organiza el diccionario por columnas: las claves son letter y code, y dentro están los índices. Nosotros queremos la letra como clave y el código como valor. Por eso el curso pide construirlo con una comprensión.

Versión 2 — El diccionario fonético (paso 1). Usa el patrón del curso y reemplaza cada palabra clave:

Texto
{new_key: new_value for (index, row) in df.iterrows()}

🧩 Tu turno: ¿qué va en new_key? ¿Qué va en new_value? ¿Cómo se llama el DataFrame? (Consejo del curso: si te atascas, vuelve a los ejemplos de main.py, imprime index y row y observa qué contienen.)

Cuando lo tengas, imprime el diccionario y compáralo con la salida de to_dict().

Versión 3 — Pedir la palabra (paso 2). Las claves del diccionario están en mayúsculas, así que la entrada también debe estarlo:

Python
word = input("Enter a word: ").upper()

Versión final — La lista de códigos. Con una comprensión de listas: la list es la palabra, cada item es una letra y el new_item es el valor del diccionario para esa letra (diccionario[letra]).

Solución del curso (en palabras): phonetic_dict = {row.letter: row.code for (index, row) in data.iterrows()} y output_list = [phonetic_dict[letter] for letter in word]. Consúltala solo después de intentarlo.

🛠️ Nota técnica (verificada): iterrows() es cómodo para aprender, pero lento con tablas grandes. Una alternativa corta que produce el mismo diccionario es dict(zip(data.letter, data.code)) (verificado). Ambas son válidas: la del curso practica comprensiones y la alternativa muestra otra herramienta de Python.

Pruebas

Entrada Resultado esperado
angela ['Alfa', 'November', 'Golf', 'Echo', 'Lima', 'Alfa']
THOMAS ['Tango', 'Hotel', 'Oscar', 'Mike', 'Alfa', 'Sierra']
ana maria (con espacio) ⚠️ ¿Qué pasa? (ver 🧪)
Muñoz ⚠️ ¿Qué pasa? (ver 🧪)
1234 ⚠️ ¿Qué pasa? (ver 🧪)

🧪 Prueba y depuración

Ejecuta los tres últimos casos y anota el error. Verificación de esta adaptación:

  • Con un espacio: KeyError: ' '. El espacio no es una clave del diccionario.
  • Con Muñoz: KeyError: 'Ñ'. El alfabeto OTAN tiene las 26 letras del inglés; la Ñ no está. Este problema afecta directamente a los nombres en español.
  • Con números: KeyError: '1'.

Preguntas para depurar:

  1. ¿En qué línea exacta se produce el error? ¿Por qué ahí y no en el input?
  2. ¿Podrías filtrar las letras que no estén en el diccionario con la comprensión condicional de la sección 2? ¿Qué desventaja tiene ocultarle al usuario que parte de su palabra no se deletreó?
  3. ¿Qué código propondrías para la Ñ? (En el Día 30 volveremos a este proyecto y manejaremos estos errores con excepciones.)

⭐ Extensión del proyecto

  • Aceptar frases: mostrar (espacio) o una línea en blanco entre palabras.
  • Agregar al CSV los dígitos del 0 al 9 (el alfabeto OTAN también los tiene; investígalos y cita la fuente).
  • Mostrar el resultado como un texto listo para leer: "Alfa - November - Golf - ...". (Pista: el método join de los strings; lo usaremos en el Día 29.)

7. 🌟 Proyecto extra: el codificador Morse de la emisora escolar

Situación

La emisora escolar quiere hacer una sección de "mensajes secretos" en código Morse. Necesitan una herramienta de consola que codifique un mensaje (texto → Morse) y lo decodifique (Morse → texto).

Requisitos

  1. Datos: construye morse.csv con las columnas caracter y codigo para las 26 letras y los 10 dígitos. Busca la tabla en una fuente confiable y cítala en un comentario del programa.
  2. Diccionarios: con comprensiones, crea el diccionario para codificar ({"A": ".-", ...}) y, a partir de él, el diccionario invertido para decodificar ({".-": "A", ...}).
  3. Codificar: las letras se separan con un espacio y las palabras con /. Ejemplo: "SOS AYUDA" → "... --- ... / .- -.-- ..- -.. .-".
  4. Decodificar: el proceso inverso. (Pista: split(" / ") y luego split(" ").)
  5. Menú: el usuario elige c (codificar), d (decodificar) o s (salir).
  6. Decisión que debes tomar: ¿qué haces con los caracteres que no están en la tabla (Ñ, tildes, signos)? ¿Los omites, los reemplazas (Ñ → N, Á → A) o avisas al usuario? Justifica tu elección en un comentario.

Restricciones técnicas

  • Al menos tres comprensiones (de listas o de diccionarios), una de ellas condicional.
  • Nada de for con append para construir listas.

Casos de prueba

Entrada Modo Esperado
sos Codificar ... --- ...
... --- ... Decodificar SOS
hola mundo Codificar y luego decodificar el resultado HOLA MUNDO
Ñandú Codificar Lo que decidiste en el requisito 6, sin que el programa se detenga con un error

Reflexión

El código Morse y el alfabeto OTAN resuelven el mismo tipo de problema: transmitir información sin ambigüedad por un canal con ruido. ¿Qué otros sistemas conoces que resuelvan ese problema? (Piensa en códigos de barras, códigos QR, lenguaje de señas…)


8. 🧩 Comprueba lo aprendido

Conceptuales

  1. Escribe el patrón de palabras clave de una comprensión de listas condicional y explica cada parte.
  2. ¿Qué diferencia hay entre [x for x in datos] y {x: 0 for x in datos}?
  3. ¿Por qué data.to_dict() no sirvió para el proyecto de la OTAN?

Análisis de código

Python
palabras = ["sol", "Luna", "mar", "Estrella"]
resultado = [p.lower() for p in palabras if p[0].isupper()]

Explica con tus palabras qué hace cada parte. ¿Qué contiene resultado?

Predicción

¿Qué imprime cada línea? Escribe tu respuesta antes de ejecutarla.

Python
print([n * n for n in range(4)])
print({n: n % 2 == 0 for n in range(1, 4)})
print([letra for letra in "banana" if letra != "a"])

Depuración

Este código debería crear un diccionario con los estudiantes que reprobaron. Tiene tres errores. Encuéntralos y corrígelos.

Python
notas = {"Ana": 4.2, "Luis": 2.9, "Sofía": 2.5}
reprobados = [nombre: nota for (nombre, nota) in notas.items if nota > 3.0]

Modificación

Modifica el proyecto de la OTAN para que, en lugar de una lista, imprima una línea por letra: A → Alfa.

Creación

Con ventas = {"empanadas": 45, "jugos": 12, "arepas": 30, "tintos": 8} (ventas de la tienda escolar en un día), crea en una línea un diccionario con los productos que vendieron más de 10 unidades y su venta aumentada en 10 %, como meta para mañana.


9. 🤖 Programar con apoyo de IA

Las comprensiones son cortas, y eso a veces las hace difíciles de leer. Una IA puede escribir comprensiones muy largas y "elegantes" que ni tú ni tus compañeros entienden.

Actividad: traducir en ambos sentidos.

  1. Escribe tú una comprensión condicional de los retos de este tutorial.
  2. Pídele a una IA que la convierta en un bucle for tradicional y que explique cada línea.
  3. Ejecuta ambas versiones con los mismos datos y comprueba que den exactamente el mismo resultado.
  4. Ahora al revés: pídele a la IA que convierta en comprensión un bucle que tenga dos condiciones anidadas. ¿El resultado es más fácil o más difícil de leer que el bucle?
  5. Pregúntale: "¿Cuándo no debería usar una comprensión de listas?". Contrasta su respuesta con la documentación oficial de Python sobre comprensiones (se abre en otra pestaña).
  6. Escribe en tu cuaderno una regla propia para decidir cuándo usar una comprensión y cuándo un bucle.

10. 🛠️ Correcciones técnicas al material original

Archivo Afirmación o comportamiento del curso Observación Tratamiento
197 long_names pide nombres de "5 letras o más" y usa len(name) > 5 > 5 excluye los nombres de exactamente 5 letras. Con la lista del curso no se nota porque no hay ninguno (verificado) Nota técnica del Tema 2
197 Se mencionan ejercicios de práctica de comprensiones No están en la carpeta del curso Nota inicial; se reemplazan por retos de la adaptación
197 "Esto es único de Python; en otros lenguajes no hay nada comparable" Es una característica muy representativa de Python, pero otros lenguajes (por ejemplo, Haskell, del cual Python tomó la idea) tienen construcciones similares Se presenta como "muy propia de Python" en la sección 0
202 iterrows() para construir el diccionario Funciona, pero es lento con tablas grandes; dict(zip(data.letter, data.code)) da el mismo resultado (verificado) Nota técnica del proyecto
202 El programa asume que la palabra solo tiene letras del inglés Espacios, dígitos y la Ñ producen KeyError (verificado) 🧪 del proyecto; se retoma en el Día 30

11. 📋 Matriz de trazabilidad

Contenido original Archivo de origen Concepto desarrollado Ejercicio original Reto adicional Proyecto relacionado
Objetivos: comprensiones y alfabeto OTAN 196 Sección 0 — — Sección 6
Comprensión de listas, patrón de palabras clave, secuencias 197 Tema 1 new_numbers, letters_list, range_list Retos 1–4 del Tema 1 Secciones 6 y 7
Comprensión condicional 197 Tema 2 short_names, long_names Retos 1–4 del Tema 2 Sección 7
Reescribir missing_states 198 Tema 3 Juego de los estados Reto del Tema 3 Día 25
Comprensión de diccionarios, .items() 199 Tema 4 students_scores, passed_students Retos 1–4 del Tema 4 Secciones 6 y 7
Recorrer DataFrames, iterrows, row.columna 200 Tema 5 Puntaje de Angela Retos 1–4 del Tema 5 Sección 6
Proyecto OTAN: planteamiento 201 Sección 6 Pasos 1 y 2 Depuración (espacio, Ñ, números) Día 30
Proyecto OTAN: solución 202 Sección 6 Diccionario fonético y lista de salida Extensiones Día 30
(No existe en el curso original) — — — Codificador Morse Sección 7

12. 📦 Evidencias de aprendizaje del Día 26

  • Los ejercicios originales resueltos en la consola de Python (captura del panel de variables).
  • Tu versión del juego de los estados con missing_states en una línea.
  • El deletreador OTAN funcionando, con la tabla de pruebas completa, incluidos los casos que fallan y tu explicación de por qué fallan.
  • El codificador Morse (proyecto extra) con su morse.csv y la fuente citada.
  • Cuaderno de errores: NameError por nombres distintos en la comprensión, SyntaxError por el if mal ubicado, .items sin paréntesis, to_dict() con el formato equivocado y KeyError con espacios, dígitos y la Ñ.