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:

  1. Bucle determinado ("voy a dar 50 escobazos"): sabés exactamente cuántas veces vas a repetir antes de empezar. En Python: for.
  2. 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:

  1. Evalúa la condición.
  2. Si es True, ejecuta el bloque.
  3. Vuelve al paso 1.
  4. 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:

  1. Antes de escribir el while, decidí quién cambia la condición y dónde.
  2. Cuando entres al bucle, releé las primeras y últimas líneas del bloque: la condición tiene que poder volverse False.
  3. Si tu programa "se cuelga", lo más probable es que sea un bucle infinito. Ctrl + C y 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 nn, el bloque interior corre n2n^2 veces. Con tres, n3n^3. 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 True con break para repetir hasta que el usuario diga "fin".
  • continue para 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 nn 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 NN y mostrá la suma 1+2+...+N1 + 2 + ... + N. Comprobá tu programa con N=100N = 100 (la respuesta es 5050).

✏️ Ejercicio 6.2 — Tabla de multiplicar

Pedí un número nn y mostrá su tabla de multiplicar de 1 a 12.

✏️ 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ó.

✏️ Ejercicio 6.4 — Promedio sin saber cuántos

Pedile notas al usuario una por una. Cuando escriba -1, dejá de pedir. Mostrá el promedio.

✏️ Ejercicio 6.5 — Verificar primalidad

Un número n>1n > 1 es primo si no tiene divisores entre 22 y n1n-1. Pedile un número y decí si es primo.

✏️ Ejercicio 6.6 — Pirámide de números

Pedile un entero NN y dibujá una pirámide así (para N=5N = 5):

    1
   222
  33333
 4444444
555555555

(Cada fila ii tiene ii repetido 2i12i - 1 veces, centrado.)

6.11 Para profundizar


Definiciones nuevas: bucle, iteración, while, for, range, break, continue, contador, acumulador, off-by-one, bucle infinito, enumerate.