Bucles: repetir tareas
"Si tu computadora no está haciendo lo mismo varias veces, no la estás aprovechando." — anónimo.
Qué vas a aprender en este capítulo
Las computadoras son rápidas haciendo cosas repetitivas — eso es el motivo principal de su existencia. En este capítulo aprendés a pedirle a Python que repita una tarea, ya sea un número fijo de veces o mientras se cumpla una condición. Vas a saber cuándo elegir for y cuándo while, vas a usar range para generar secuencias de números, y vas a aprender a salir de un bucle cuando la cosa se complica.
6.1 La idea: barrer el patio
💡 Intuición
Imaginate que tenés que barrer el patio. No barrés con una sola escobada y listo — repetís un movimiento (escoba, escoba, escoba…) hasta que el patio queda limpio. Ese "hasta que" es la base de un bucle: una acción y una condición de salida.
Hay dos formas de pensarlo:
- Bucle determinado ("voy a dar 50 escobazos"): sabés exactamente cuántas veces vas a repetir antes de empezar. En Python:
for. - Bucle indeterminado ("voy a barrer hasta que esté limpio"): no sabés cuántas veces, repetís mientras se cumpla algo. En Python:
while.
Las dos formas existen porque cada una se acomoda mejor a problemas distintos. Recorrer una lista de notas: for. Pedir input al usuario hasta que escriba algo válido: while. Aprender a elegir es parte del oficio.
Sin bucles, una computadora es una calculadora con esteroides. Con bucles, es una herramienta que multiplica horas humanas por miles.
6.2 while: repetir mientras
📐 Fundamento
while condicion:
# bloque que se repite
instrucciones
Cómo funciona Python:
- Evalúa la condición.
- Si es
True, ejecuta el bloque. - Vuelve al paso 1.
- Si es
False, sigue con la primera línea fuera del bucle.
Ejemplo: contar de 1 a 5.
n = 1
while n <= 5:
print(n)
n += 1
print("Listo")
Salida:
1
2
3
4
5
Listo
Ejemplo: validar entrada.
edad = int(input("Edad: "))
while edad < 0 or edad > 120:
print("Edad inválida.")
edad = int(input("Edad: "))
print(f"Edad registrada: {edad}")
Mientras la edad no esté en rango, vuelve a preguntar. Cuando finalmente da bien, el bucle termina.
Patrón clave: contadores y acumuladores.
# Sumar los primeros 10 números
total = 0 # acumulador
n = 1 # contador
while n <= 10:
total += n
n += 1
print(total) # 55
El acumulador empieza en su elemento neutro (0 para suma, 1 para producto, lista vacía para colecciones). El contador avanza paso a paso.
⚠️ Trampa común
El bucle infinito. Si te olvidás de actualizar la variable que controla la condición, el bucle no termina jamás:
n = 1
while n <= 5:
print(n) # ¡faltó n += 1!
Esto imprime 1 para siempre. Cómo salir: en la terminal, Ctrl + C aborta el programa. En Pydroid, hay un botón rojo de stop.
Cómo prevenirlos:
- Antes de escribir el
while, decidí quién cambia la condición y dónde. - Cuando entres al bucle, releé las primeras y últimas líneas del bloque: la condición tiene que poder volverse
False. - Si tu programa "se cuelga", lo más probable es que sea un bucle infinito.
Ctrl + Cy revisar.
Off-by-one. El error más común al usar while:
n = 1
while n < 5: # ¿llega hasta 4 o hasta 5?
print(n)
n += 1
# Imprime: 1 2 3 4. ¡No llega a 5!
Para incluir 5, usá n <= 5. Cuando dudes, probá con un valor pequeño (1 a 3) y contá. Las matemáticas hablan en intervalos cerrados o abiertos según convenga. La programación también.
6.3 for con range: repetir N veces
📐 Fundamento
for es para cuando sabés cuántas veces querés repetir, o cuántos elementos querés recorrer. La forma básica con range:
for i in range(5):
print(i)
Salida:
0
1
2
3
4
range(5) genera la secuencia 0, 1, 2, 3, 4. Empieza en 0 y NO incluye el 5. Esto es inclusivo-exclusivo, una convención que vas a ver en muchos lenguajes y que vas a amar después de odiar al principio.
Las tres formas de range:
| Llamada | Genera |
|---|---|
range(n) |
0, 1, 2, ..., n-1 |
range(a, b) |
a, a+1, ..., b-1 |
range(a, b, paso) |
a, a+paso, a+2*paso, ... (mientras < b) |
Ejemplos:
for i in range(1, 6): # 1, 2, 3, 4, 5
print(i)
for i in range(0, 21, 5): # 0, 5, 10, 15, 20
print(i)
for i in range(10, 0, -1): # 10, 9, 8, ..., 1 (cuenta atrás)
print(i)
Por qué empieza en 0. Es la convención más útil para programar — coincide con los índices de las colecciones (que vamos a ver en cursos siguientes). El primer elemento de una lista en Python tiene índice 0, no 1. Acostumbrate desde acá.
Equivalencia for-while. El for i in range(n): es equivalente a:
i = 0
while i < n:
# ...
i += 1
Pero el for es:
- Más corto.
- Imposible de hacer infinito por error (la variable se actualiza sola).
- Más expresivo — el lector entiende inmediatamente "esto se repite N veces".
Conclusión: cuando sepas cuántas veces, for. Cuando dependa de una condición externa (input, sensor, archivo), while.
6.4 for recorriendo otras cosas
for no es solo para range. Recorre cualquier cosa iterable — cadenas, listas, tuplas, archivos…
# Recorrer una cadena: cada iteración te da un carácter
for letra in "Pupusa":
print(letra)
Salida:
P
u
p
u
s
a
# Recorrer una lista (lo profundizás en cursos siguientes; usalo igual)
sabores = ["queso", "revuelta", "chicharron", "frijol"]
for sabor in sabores:
print(f"- Pupusa de {sabor}")
Esa es la forma idiomática ("pythonic") de recorrer una colección. No hace falta range(len(...)) y acceder por índice; for x in coleccion: ya te da los elementos directo.
enumerate — cuando necesités tanto el elemento como su posición:
sabores = ["queso", "revuelta", "chicharron"]
for i, sabor in enumerate(sabores, start=1):
print(f"{i}. Pupusa de {sabor}")
Salida:
1. Pupusa de queso
2. Pupusa de revuelta
3. Pupusa de chicharron
enumerate devuelve pares (índice, elemento) que descompongo en i y sabor con la coma. start=1 es para empezar en 1 en lugar de 0 — útil para usuarios humanos.
6.5 break y continue
📐 Fundamento
A veces necesitás interrumpir un bucle antes de que termine naturalmente:
break — sale del bucle inmediatamente.
# Buscar el primer múltiplo de 7 mayor que 100
n = 100
while True: # bucle infinito intencional
n += 1
if n % 7 == 0:
print(f"Encontrado: {n}")
break # cortamos acá
continue — salta a la próxima iteración (no ejecuta lo que sigue del bloque).
# Imprimir solo los pares entre 1 y 10
for n in range(1, 11):
if n % 2 != 0:
continue # salta los impares
print(n)
Trade-off. break y continue rompen la lectura "lineal" del bucle: ya no es "haga lo mismo N veces", sino "haga lo mismo, pero a veces salga, a veces salte". Eso a veces es lo más natural; otras veces es más limpio escribir mejor la condición. Regla práctica: usá break cuando termines de buscar o necesités salir por error; usá continue para filtrar elementos.
Ejemplo combinando: validar entrada.
while True:
s = input("Edad: ").strip()
if not s:
print("No puede estar vacío.")
continue
try:
edad = int(s)
except ValueError:
print("No es un número.")
continue
if edad < 0 or edad > 120:
print("Fuera de rango.")
continue
break # solo se llega acá si pasó las tres pruebas
print(f"Edad registrada: {edad}")
try/except es nuestra primera defensa contra entradas inválidas. Lo profundizamos en Programación II; por ahora, este patrón te alcanza.
6.6 else en bucles (poco usado, pero existe)
Python tiene una rareza simpática: un else puede ir adjunto a un for o while. Se ejecuta si el bucle terminó normalmente (sin break).
# Buscar un número primo hasta 20
n = int(input("n: "))
for i in range(2, n):
if n % i == 0:
print(f"{n} no es primo (divisible por {i})")
break
else:
print(f"{n} es primo")
Si el for agota su rango sin encontrar divisor (no hubo break), entra al else. Útil para "buscar hasta que" patrones.
Ojo: muchos programadores no conocen este else y se confunden. Si vas a usarlo, dejá un comentario corto explicando.
6.7 Bucles anidados
Un bucle puede contener otro:
# Tabla de multiplicar 1..5
for i in range(1, 6):
for j in range(1, 6):
print(f"{i} x {j} = {i*j}")
print() # línea en blanco entre tablas
Patrón clásico — buscar algo:
# Buscar dos números en 1..10 cuya suma sea 13
for a in range(1, 11):
for b in range(a + 1, 11):
if a + b == 13:
print(f"{a} + {b} = 13")
Costo computacional. Con dos for anidados de tamaño , el bloque interior corre veces. Con tres, . Un proyecto real con n grande se vuelve lento muy rápido — la asignatura Estructuras de Datos y Algoritmos se dedica casi enteramente a evitar bucles anidados innecesarios.
6.8 Proyecto: pedidos múltiples en la pupusería
🏗️ Avance del proyecto — Pupusería La Esquina
Hasta acá, la pupusería atiende un solo cliente y se cierra. Ahora vamos a aceptar múltiples pedidos hasta que la cajera escriba "fin". Cada pedido es de una sola variedad (lo simplificamos). Al final, mostramos el total del día.
# Pupuseria La Esquina - Capitulo 6: pedidos en bucle
precios = {
"queso": 0.50,
"revuelta": 0.60,
"chicharron": 0.60,
}
IVA = 0.13
total_dia = 0
clientes = 0
print("=== Pupuseria La Esquina ===")
print("Escribí 'fin' para cerrar la caja.\n")
while True:
sabor = input("Sabor (queso/revuelta/chicharron) o 'fin': ").strip().lower()
if sabor == "fin":
break
if sabor not in precios:
print(f" No tenemos '{sabor}'. Probá de nuevo.")
continue
cantidad_str = input(" Cantidad: ").strip()
if not cantidad_str.isdigit() or int(cantidad_str) <= 0:
print(" Cantidad inválida.")
continue
cantidad = int(cantidad_str)
subtotal = cantidad * precios[sabor]
total = subtotal * (1 + IVA)
print(f" Total: ${total:.2f}\n")
total_dia += total
clientes += 1
print()
print("=========== CIERRE DE CAJA ===========")
print(f" Clientes atendidos: {clientes}")
print(f" Total del día: ${total_dia:.2f}")
if clientes > 0:
print(f" Ticket promedio: ${total_dia / clientes:.2f}")
print("======================================")
Lo nuevo en este capítulo:
while Trueconbreakpara repetir hasta que el usuario diga "fin".continuepara volver a pedir cuando hay datos inválidos.- Diccionario
precios. Lo introducimos sin explicarlo en detalle:precios["queso"]te da el precio. Es como un diccionario humano: una palabra (la "llave") apunta a un valor. - Acumular total y conteo en variables externas al bucle.
Cosas que todavía no manejamos elegantemente:
- Modificar el menú sin tocar el código fuente (necesitamos archivos).
- Que un mismo cliente pida varias variedades en un mismo recibo (necesitamos una lista de líneas).
Eso queda para Programación II.
6.9 Resumen visual
| Forma | Para qué |
|---|---|
for i in range(n): |
Repetir veces. |
for x in coleccion: |
Recorrer cada elemento. |
for i, x in enumerate(c): |
Recorrer con índice. |
while condicion: |
Repetir mientras se cumpla. |
while True: ... break |
Repetir hasta que adentro decidas salir. |
break |
Salir del bucle ya. |
continue |
Saltar a la próxima iteración. |
| Cosa que evitar | Pista |
|---|---|
| Bucle infinito | La variable de control no cambia. |
| Off-by-one | Confundir < con <=. |
| Anidación demasiado profunda | Más de tres for anidados → repensá. |
6.10 Ejercicios
✏️ Ejercicio 6.1 — Suma de los primeros N números
Pedile un entero y mostrá la suma . Comprobá tu programa con (la respuesta es 5050).
Solución
n = int(input("N: "))
total = 0
for i in range(1, n + 1):
total += i
print(f"Suma: {total}")
Versión sin bucle: la fórmula de Gauss te da :
print(n * (n + 1) // 2)
Las dos llegan al mismo resultado, pero la fórmula es infinitamente más rápida para grande. Aprender a buscar atajos matemáticos es un superpoder a largo plazo.
✏️ Ejercicio 6.2 — Tabla de multiplicar
Pedí un número y mostrá su tabla de multiplicar de 1 a 12.
Solución
n = int(input("Número: "))
for i in range(1, 13):
print(f"{n} x {i} = {n * i}")
✏️ Ejercicio 6.3 — Adivinanza
El programa "piensa" un número entre 1 y 100 (podés codificarlo a mano: secreto = 42). El usuario intenta adivinarlo. En cada intento el programa dice "más alto" o "más bajo". Cuando acierta, mostrá cuántos intentos le tomó.
Solución
secreto = 42
intentos = 0
while True:
g = int(input("Adivinás: "))
intentos += 1
if g < secreto:
print("Más alto")
elif g > secreto:
print("Más bajo")
else:
print(f"¡Acertaste en {intentos} intentos!")
break
Bonus: para que el secreto sea aleatorio:
import random
secreto = random.randint(1, 100)
✏️ Ejercicio 6.4 — Promedio sin saber cuántos
Pedile notas al usuario una por una. Cuando escriba -1, dejá de pedir. Mostrá el promedio.
Solución
total = 0
cantidad = 0
while True:
n = float(input("Nota (-1 para terminar): "))
if n == -1:
break
if n < 0 or n > 10:
print("Nota inválida.")
continue
total += n
cantidad += 1
if cantidad == 0:
print("No hay notas.")
else:
print(f"Promedio: {total / cantidad:.2f}")
Patrón importante: cuando dividís, siempre verificá que el divisor no sea cero. La división por cero es uno de los errores más fáciles de cometer y de los más vergonzosos en producción.
✏️ Ejercicio 6.5 — Verificar primalidad
Un número es primo si no tiene divisores entre y . Pedile un número y decí si es primo.
Solución
n = int(input("n: "))
if n < 2:
print(f"{n} no es primo")
else:
es_primo = True
for i in range(2, n):
if n % i == 0:
es_primo = False
break
print(f"{n} es {'primo' if es_primo else 'NO primo'}")
Optimización clásica: alcanza con probar hasta — si tiene un divisor mayor, también tiene uno menor. Vale la pena mencionarlo:
import math
limite = int(math.sqrt(n)) + 1
for i in range(2, limite):
if n % i == 0:
...
Esa optimización transforma un programa lentísimo (probar hasta 1 millón si 1 millón) en uno rápido (solo hasta 1000). Algoritmos eficientes es el tema de tercer ciclo.
✏️ Ejercicio 6.6 — Pirámide de números
Pedile un entero y dibujá una pirámide así (para ):
1
222
33333
4444444
555555555
(Cada fila tiene repetido veces, centrado.)
Solución
n = int(input("N: "))
for i in range(1, n + 1):
espacios = " " * (n - i)
digitos = str(i) * (2 * i - 1)
print(espacios + digitos)
Bucle anidado sin escribirlo porque * ya repite por nosotros. La concatenación con + arma cada línea. La construcción " " * k y "x" * k es un patrón común para padding.
6.11 Para profundizar
- Documentación oficial: https://docs.python.org/es/3/tutorial/controlflow.html — los apartados sobre
for,range,break/continue. - Bucles eficientes: la asignatura Estructuras de Datos y Algoritmos profundiza por qué los bucles anidados se vuelven lentos y cómo evitarlos. Los términos clave son "complejidad temporal" y notación O grande.
- Próximo capítulo: Funciones — empaquetar lógica en cajas reutilizables, el principio DRY ("Don't Repeat Yourself"), y la antesala a la recursión.
Definiciones nuevas: bucle, iteración, while, for, range, break, continue, contador, acumulador, off-by-one, bucle infinito, enumerate.