Flujo de control
Cada programa que has escrito hasta ahora se ejecuta de la misma manera todas las veces: de arriba hacia abajo, una línea a la vez. Eso funciona para scripts simples, pero los programas reales necesitan tomar decisiones y repetir tareas. Un cuestionario necesita verificar si la respuesta es correcta. Un juego necesita seguir corriendo hasta que el jugador gane o pierda. Este capítulo cubre cómo hacer que tu programa se bifurque y repita.
Comparaciones
Antes de poder tomar una decisión, necesitas comparar cosas. Los operadores de comparación devuelven True o False. El más importante de entender desde el inicio: = asigna un valor, == verifica si dos valores son iguales. Confundirlos es uno de los errores más comunes de los principiantes.
5 > 3 # True
5 < 3 # False
5 == 5 # True (nota: doble igual; = es asignación, == es comparación)
5 != 3 # True ("distinto de")
5 >= 5 # True ("mayor o igual que")
5 <= 4 # False ("menor o igual que")La distinción entre = y == confunde a casi todos al principio. La asignación (=) almacena un valor; la comparación (==) verifica si dos valores son iguales.
También puedes comparar strings. Python los compara alfabéticamente:
"manzana" == "manzana" # True
"manzana" < "banana" # False (b viene antes que m)
"manzana" == "Manzana" # False (distingue mayúsculas y minúsculas)Combinando condiciones
and, or y not combinan comparaciones. and requiere que ambos lados sean verdaderos. or requiere al menos un lado. not invierte el resultado. Estos te permiten expresar condiciones del mundo real como "el puntaje es aprobatorio Y el usuario está activo".
edad = 25
puntaje = 88
edad >= 18 and puntaje >= 80 # True (ambos deben ser verdaderos)
edad < 18 or puntaje >= 80 # True (al menos uno debe ser verdadero)
not edad >= 18 # False (invierte el resultado)and requiere ambos lados. or requiere al menos un lado. not invierte.
Verdadero y falso (truthy y falsy)
Cada valor en Python tiene una interpretación booleana, incluso si no es True o False. Los strings vacíos, el cero, las listas vacías y None se comportan como False en una condición. Todo lo demás se comporta como True. Esto significa que if results: verifica si una lista no está vacía sin tener que escribir if len(results) > 0:.
# Todos estos se comportan como False en una condición:
False, 0, 0.0, "", [], {}, (), None
# Todo lo demás se comporta como TrueEsto significa que if results: es una forma natural de decir "si la lista no está vacía", y if name: verifica si un string tiene algún contenido.
if / elif / else
La sentencia if ejecuta un bloque de código solo cuando su condición es True. elif agrega más condiciones para verificar si la primera fue falsa. else captura todo lo que no coincidió con ninguna condición. Python usa indentación, no llaves, para definir qué pertenece dentro de cada bloque.
puntaje = 87
if puntaje >= 90:
print("Calificación A")
elif puntaje >= 80:
print("Calificación B")
elif puntaje >= 70:
print("Calificación C")
else:
print("Por debajo de C")Las reglas:
ifes obligatorio y siempre va primeroelif(abreviatura de "else if") es opcional y puedes tener tantos como necesiteselsees opcional, maneja todo lo que no coincidió y va al final- Python usa indentación (4 espacios) para marcar qué pertenece dentro de cada bloque; no hay llaves
La indentación no es opcional ni cosmética. Python la usa para definir la estructura. La indentación inconsistente es un error de sintaxis.
Condiciones de una línea
Para asignaciones simples de sí/no, Python tiene una forma compacta de una línea llamada expresión ternaria: valor_si_verdadero if condicion else valor_si_falso. Úsala solo cuando la lógica sea genuinamente simple y se lea como una oración.
etiqueta = "aprobado" if puntaje >= 50 else "reprobado"Esta es una expresión ternaria; se lee como una oración. Úsala cuando la lógica sea genuinamente simple. Para cualquier cosa que involucre elif, escribe la versión completa.
Bucles while
Un bucle while repite su bloque mientras su condición sea True. Úsalo cuando no sepas de antemano cuántas veces debe ejecutarse el bucle, por ejemplo esperando una entrada válida o reintentando hasta que una tarea tenga éxito.
vidas = 3
while vidas > 0:
print(f"Vidas restantes: {vidas}")
vidas -= 1
print("Fin del juego")while es mejor cuando no sabes de antemano cuántas veces se ejecutará el bucle. Cuando sí lo sabes, o cuando estás iterando sobre una colección, for es más limpio.
break y continue
break sale del bucle inmediatamente, sin importar cuántas iteraciones queden. continue omite el resto de la iteración actual y salta de regreso a la verificación de la condición. Ambos solo afectan al bucle más interno en el que están.
break sale del bucle inmediatamente:
objetivo = 5
num = 0
while True:
num += 1
if num == objetivo:
print(f"Encontrado {objetivo}")
break # detiene el buclewhile True: con un break es un patrón válido y común cuando la condición de salida es compleja o necesita ocurrir al final del cuerpo del bucle.
continue omite el resto de la iteración actual y vuelve a la verificación de la condición:
num = 0
while num < 10:
num += 1
if num % 2 == 0:
continue # omite los números pares
print(num) # solo imprime los impares: 1, 3, 5, 7, 9Bucles for
Un bucle for recorre una secuencia un elemento a la vez: una lista, un string, un rango de números. La variable que nombras después de for recibe cada elemento por turno. Tú no gestionas un contador ni verificas la longitud.
jugadores = ["Sofía", "Mateo", "Valentina"]
for jugador in jugadores:
print(f"¡Hola, {jugador}!")Los bucles for también funcionan con strings (iterando carácter por carácter) y con cualquier otro tipo de secuencia.
range()
range() genera una secuencia de números para que recorras. range(5) te da 0, 1, 2, 3, 4. Puedes controlar el inicio, el final y el tamaño del paso. Úsalo cuando necesites que un bucle se ejecute un número específico de veces.
for i in range(5):
print(i) # 0, 1, 2, 3, 4range() tiene tres formas:
| Llamada | Lo que produce |
|---|---|
range(5) | 0, 1, 2, 3, 4 |
range(2, 6) | 2, 3, 4, 5 |
range(0, 10, 2) | 0, 2, 4, 6, 8 (paso de 2) |
range(5, 0, -1) | 5, 4, 3, 2, 1 (contando hacia atrás) |
range() no crea una lista. Produce números uno a la vez, lo que es eficiente incluso para rangos muy grandes.
enumerate()
enumerate() te da tanto el índice como el valor mientras recorres, así no necesitas llevar un contador por separado. La parte i, jugador recibe automáticamente un par de valores en cada iteración.
jugadores = ["Sofía", "Mateo", "Valentina"]
for i, jugador in enumerate(jugadores):
print(f"{i + 1}. {jugador}")
# 1. Sofía
# 2. Mateo
# 3. ValentinaLa sintaxis i, jugador se llama desempaque. Python divide el par (índice, valor) en dos nombres automáticamente.
Por defecto enumerate() comienza en 0. Pasa un valor inicial para cambiarlo:
for i, jugador in enumerate(jugadores, start=1):
print(f"{i}. {jugador}") # comienza en 1Bucles anidados
Puedes poner un bucle dentro de otro bucle. El bucle interno se ejecuta completamente por cada iteración del bucle externo. Así es como procesas cuadrículas, combinaciones o cualquier dato con dos niveles de estructura.
filas = [1, 2, 3]
columnas = ["A", "B"]
for fila in filas:
for col in columnas:
print(f"{col}{fila}", end=" ")
print() # nueva línea después de cada fila
# A1 B1
# A2 B2
# A3 B3break y continue dentro de un bucle anidado solo afectan al bucle más interno.
Loop-else
Los bucles de Python pueden tener una cláusula else que se ejecuta solo si el bucle terminó sin encontrar un break. No se usa comúnmente, pero es la forma más limpia de escribir "buscar en una lista, y si no se encontró nada, hacer esto".
objetivo = "Diego"
nombres = ["Sofía", "Mateo", "Valentina"]
for nombre in nombres:
if nombre == objetivo:
print(f"Encontrado {objetivo}")
break
else:
print(f"{objetivo} no está en la lista") # se ejecuta porque break nunca se disparóSi se ejecuta break, el else se omite. Si el bucle agota la secuencia, else se ejecuta. Es un patrón de nicho pero más limpio que una variable bandera.
Ordenamiento
sorted() devuelve una nueva lista ordenada y deja la original sin cambios. .sort() ordena la lista en el lugar y devuelve None. El argumento key= te permite ordenar por algo distinto al valor crudo. Por ejemplo, ordenar nombres sin distinguir mayúsculas o ordenar tuplas de jugadores por su puntaje.
puntajes = [87, 42, 96, 55, 71]
ranking = sorted(puntajes) # [42, 55, 71, 87, 96] (nueva lista)
puntajes.sort() # ordena la lista original, devuelve None
puntajes.sort(reverse=True) # [96, 87, 71, 55, 42]Ambos aceptan un argumento key=: una función aplicada a cada elemento antes de la comparación:
nombres = ["Valentina", "Sofía", "Mateo"]
sorted(nombres, key=str.lower) # ordenamiento sin distinguir mayúsculas
jugadores = [("Sofía", 87), ("Mateo", 96), ("Valentina", 55)]
sorted(jugadores, key=lambda p: p[1]) # ordenar por puntaje¿Qué es un lambda?
lambda p: p[1] es una función de una línea. Toma una tupla de jugador y devuelve el puntaje. Las funciones lambda se cubren en el capítulo Lambda, comprensiones y zip.
Para casos simples, usa sorted(). Para listas donde quieras modificar en el lugar, usa .sort().
En la práctica
Recorre puntajes, acumula un total, cuenta las notas aprobatorias e imprime un resumen:
puntajes_crudos = [87, 42, 96, 55, 71, 63]
total = 0
aprobados = 0
for puntaje in puntajes_crudos:
total += puntaje
if puntaje >= 60:
aprobados += 1
promedio = total / len(puntajes_crudos)
print(f"Promedio: {promedio:.1f}")
print(f"Aprobados: {aprobados}/{len(puntajes_crudos)}")
print(f"Puntaje más alto: {sorted(puntajes_crudos, reverse=True)[0]}")
