Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:programacion_desde_cero_con_python:bucles_y_repeticion

Bucles y repetición

En este módulo verás cómo automatizar tareas con while y for.

Este módulo forma parte del curso de programación desde cero con Python

Módulo 7. Bucles y repetición

En el Módulo 6 aprendiste a que tu programa decidiera entre varios caminos, pero cada instrucción se ejecuta, como mucho, una vez. Imagina que quieres saludar a diez usuarios, validar cien contraseñas o procesar mil registros. Escribir el mismo bloque de código repetido cien veces no es programar: es transcribir. Los bucles existen para repetir instrucciones de forma controlada, y son la herramienta que convierte un script rígido en un programa capaz de automatizar tareas repetitivas.


1. Título y alcance

Título: Bucles y repetición: automatizar tareas con while y for.

Alcance: Comprender la necesidad de repetir instrucciones; usar while para repetir mientras se cumpla una condición; usar for para recorrer secuencias e iterables; generar secuencias numéricas con range(); aplicar contadores y acumuladores; controlar la ejecución con break y continue; entender la cláusula else de los bucles; construir bucles anidados; diagnosticar y evitar bucles infinitos; y elegir la estructura de repetición adecuada según el problema. Se presupone el uso de variables, tipos, condiciones (if/elif/else) y entrada/salida, pero no se introducen funciones propias (Módulo 9) ni colecciones avanzadas (Módulo 8).


2. Objetivos de aprendizaje

Al terminar este módulo serás capaz de:

1. Explicar cuándo un problema requiere un bucle y cuándo no. 2. Escribir bucles while con una condición de terminación clara y una actualización que garantice que el bucle finaliza. 3. Escribir bucles for para recorrer cadenas, listas y otros iterables. 4. Usar range() con uno, dos y tres argumentos para generar progresiones aritméticas. 5. Implementar contadores (para contar ocurrencias) y acumuladores (para sumar valores). 6. Usar break para salir anticipadamente de un bucle y continue para saltar el resto de una iteración. 7. Explicar y aplicar la cláusula else de los bucles, entendiendo que se ejecuta cuando el bucle no se interrumpe con break. 8. Construir bucles anidados y comprender el orden de ejecución. 9. Detectar las causas de un bucle infinito y corregirlas. 10. Elegir entre for y while según la naturaleza del problema.


3. Conocimientos previos

- Del Módulo 4: Variables, tipos (int, float, str, bool), operadores de comparación y lógicos. - Del Módulo 5: input(), conversión de tipos y f-strings. - Del Módulo 6: if/elif/else, condiciones compuestas, truthiness, expresión condicional y match/case. - Ningún conocimiento de bucles ni de iterables.


4. Introducción motivadora: el programa que solo funciona una vez

Un programa que pide una contraseña y la comprueba una sola vez es fácil de burlar: basta con volver a ejecutarlo. Un programa que pide la contraseña hasta que sea correcta es mucho más útil. Esa palabra, “hasta”, es la esencia de un bucle: repetir una acción mientras se cumpla una condición, o para cada elemento de un conjunto.

Los bucles son, junto con las condiciones, la estructura de control que da verdadera potencia a un programa. Sin ellos, no podrías procesar una lista de correos, calcular la media de cien notas ni generar una tabla de multiplicar. Con ellos, puedes escribir diez líneas de código que hagan el trabajo de mil.


5. Explicación paso a paso

5.1. `while`: repetir mientras se cumpla una condición

Un bucle while ejecuta un bloque de instrucciones mientras su condición sea verdadera. La sintaxis es:

while condición:
    # bloque que se repite

Ejemplo clásico: contar del 1 al 5.

contador = 1
while contador <= 5:
    print(contador)
    contador = contador + 1

Seguimiento:

1. contador vale 1. La condición 1 <= 5 es verdadera. Se ejecuta el bloque: se imprime 1 y contador pasa a valer 2. 2. contador vale 2. 2 <= 5 es verdadera. Se imprime 2 y contador pasa a 3. 3. … 4. contador vale 5. 5 <= 5 es verdadera. Se imprime 5 y contador pasa a 6. 5. contador vale 6. 6 <= 5 es falsa. El bucle termina.

[ERROR HABITUAL] Olvidar actualizar la variable de control dentro del bucle. Si en el ejemplo anterior eliminas contador = contador + 1, la condición 1 <= 5 siempre será verdadera y el bucle nunca terminará. Esto es un bucle infinito. La causa más común es no modificar nada que afecte a la condición.
[BUENA PRÁCTICA] Asegúrate de que el cuerpo del bucle siempre avanza hacia la terminación. Puedes usar contador += 1, que es equivalente a contador = contador + 1, pero más conciso e idiomático en Python.

5.2. `for`: recorrer una secuencia

Un bucle for en Python itera sobre los elementos de una secuencia (una cadena, una lista, una tupla, un diccionario, etc.), en el orden en que aparecen. No es un contador numérico como en C o Java; es un recorrido por elementos.

palabra = "Python"
for letra in palabra:
    print(letra)

Salida:

P
y
t
h
o
n

La variable letra toma sucesivamente cada valor de la secuencia. No necesitas índices ni condiciones de terminación: el bucle termina cuando se agotan los elementos.

[PYTHON] El for de Python es un bucle for-each, no un bucle for con contador al estilo de C (for (i = 0; i < n; i++)). Esta es una diferencia fundamental que conviene interiorizar desde el principio: en Python, iteras sobre cosas, no sobre números (a menos que uses range() para generar números).

5.3. `range()`: generar secuencias numéricas

Si necesitas iterar sobre una progresión de números, range() genera una secuencia aritmética. Acepta uno, dos o tres argumentos:

- range(fin): desde 0 hasta fin - 1. - range(inicio, fin): desde inicio hasta fin - 1. - range(inicio, fin, paso): desde inicio hasta fin - 1, avanzando de paso en paso.

for i in range(5):
    print(i)          # 0, 1, 2, 3, 4
 
for i in range(1, 6):
    print(i)          # 1, 2, 3, 4, 5
 
for i in range(0, 10, 2):
    print(i)          # 0, 2, 4, 6, 8
 
for i in range(5, 0, -1):
    print(i)          # 5, 4, 3, 2, 1
[ERROR HABITUAL] El valor final nunca se incluye. range(5) genera 0, 1, 2, 3, 4, no 0, 1, 2, 3, 4, 5. Si quieres llegar a 5, escribe range(6). Este es el mismo principio de “fin exclusivo” que viste en la segmentación de cadenas (Módulo 5).
[PYTHON] range() no crea una lista en memoria: genera los números a medida que se necesitan (es un objeto lazy). Esto lo hace eficiente incluso para rangos muy grandes, como range(1_000_000_000). Si necesitas una lista real, puedes usar list(range(...)), pero en un bucle for no es necesario.

5.4. Contadores y acumuladores

Dos patrones fundamentales que aparecen constantemente:

Contador: una variable que se incrementa (normalmente en 1) cada vez que ocurre algo.

frase = "programación"
vocales = 0
for letra in frase:
    if letra in "aeiouáéíóú":
        vocales += 1
print(f"La frase tiene {vocales} vocales.")

Acumulador: una variable que acumula una suma (u otra operación) de valores.

numeros = [10, 20, 30, 40]
suma = 0
for n in numeros:
    suma += n
print(f"La suma es {suma}.")  # 100
[BUENA PRÁCTICA] Inicializa siempre el contador o acumulador antes del bucle (vocales = 0, suma = 0). Si lo inicializas dentro, se reinicia en cada iteración y el resultado será incorrecto.

5.5. `break` y `continue`: control fino del bucle

- break sale inmediatamente del bucle, sin ejecutar las iteraciones restantes. - continue salta el resto del cuerpo del bucle y pasa a la siguiente iteración.

# break: buscar un número
for n in [3, 7, 11, 15, 20]:
    if n % 2 == 0:
        print(f"Encontrado el primer par: {n}")
        break
# Salida: Encontrado el primer par: 20 (tras recorrer 3, 7, 11, 15)
 
# continue: saltar los impares
for n in range(1, 6):
    if n % 2 != 0:
        continue
    print(n)
# Salida: 2, 4
[ERROR HABITUAL] Usar break cuando bastaría con una condición en el while o un if dentro del for. break es útil, pero abusar de él puede hacer que el flujo del programa sea difícil de seguir. Úsalo cuando la salida anticipada sea la intención clara del código (por ejemplo, “buscar hasta encontrar”).

5.6. La cláusula `else` de los bucles

Python permite añadir un else a un bucle for o while. El bloque else se ejecuta si el bucle termina de forma natural, es decir, si no se interrumpió con break. No se ejecuta si el bucle sale por un break.

numeros = [3, 7, 11, 15]
buscado = 9
 
for n in numeros:
    if n == buscado:
        print("Encontrado")
        break
else:
    print("No encontrado")  # Esta línea se ejecuta

Seguimiento: Como 9 no está en la lista, el for recorre todos los elementos sin encontrar coincidencia. No hay break, así que el else se ejecuta y muestra "No encontrado". Si buscado fuera 7, el break se ejecutaría y el else se omitiría.

[PYTHON] La cláusula else en bucles es una característica poco común en otros lenguajes y a menudo sorprende a los principiantes. No significa “si el bucle no se ejecutó”; significa “si el bucle terminó sin break”. Es útil para evitar el patrón torpe de usar una variable bandera (encontrado = False) y comprobarla después.
[ERROR HABITUAL] Confundir el else del bucle con el else del if. Son independientes. Un if dentro de un bucle puede tener su propio else; el else del bucle va al mismo nivel de indentación que el for o el while, no dentro del cuerpo.

5.7. Bucles anidados

Un bucle dentro de otro bucle. Por cada iteración del bucle externo, el interno se ejecuta completo.

for i in range(1, 4):
    for j in range(1, 4):
        print(f"{i} x {j} = {i * j}")
    print("---")

Seguimiento: Para i = 1, j recorre 1, 2, 3 e imprime tres productos; luego ---. Después i = 2, y así sucesivamente. El número total de iteraciones es 3 * 3 = 9.

[BUENA PRÁCTICA] Los bucles anidados son útiles para tablas, matrices y combinaciones, pero su coste crece rápidamente (un bucle de 1000 dentro de otro de 1000 son un millón de iteraciones). Si notas que el programa se vuelve lento, revisa si puedes reducir el anidamiento.

5.8. Bucles infinitos: cómo detectarlos y evitarlos

Un bucle infinito es un bucle cuya condición nunca se vuelve falsa. El programa se queda “colgado” y no responde. Las causas más comunes:

1. No modificar la variable de la condición: while x < 10: sin x += 1 dentro. 2. Condición mal formulada: while x != 10: cuando x empieza en 12 y solo aumenta; nunca será exactamente 10. 3. continue antes de la actualización: si saltas la línea que modifica la variable, la condición no cambia.

# Bucle infinito: x nunca cambia
x = 1
while x <= 5:
    print(x)  # Se repite para siempre
[BUENA PRÁCTICA] Cuando escribas un while, pregúntate: “¿qué hace que esta condición se vuelva falsa?” y asegúrate de que esa acción está en el cuerpo del bucle. Si no lo está, tienes un bucle infinito.
[WINDOWS / LINUX] Para detener un bucle infinito en la terminal, pulsa Ctrl + C en ambos sistemas. Esto envía una interrupción (KeyboardInterrupt) y detiene el programa. No cierres la terminal a la fuerza si puedes evitarlo.

5.9. Elección entre `for` y `while`

Usa for cuando…Usa while cuando…
Conoces el número de iteraciones o tienes una secuencia que recorrer.No sabes cuántas iteraciones necesitarás; depende de una condición.
Iteras sobre una cadena, lista, tupla, diccionario o range().Esperas a que el usuario introduzca un valor válido.
Quieres recorrer elementos, no contar.La terminación depende de un cálculo o de una entrada externa.
[PYTHON] En Python, for es el bucle preferido cuando hay una colección de por medio. while se reserva para bucles basados en condiciones que no dependen de una secuencia predecible. Si te encuentras usando while con un contador que incrementas manualmente, probablemente for con range() sea más claro.

6. Ejemplos comentados

Ejemplo 1: Validación de contraseña con while.

# archivo: password.py
clave_correcta = "secreto"
intento = ""
 
while intento != clave_correcta:
    intento = input("Introduce la contraseña: ")
 
print("Acceso concedido.")

Seguimiento: El bucle se repite mientras intento sea distinto de "secreto". En cada iteración, input() actualiza intento, así que la condición puede volverse falsa. Si el usuario nunca acierta, el bucle continúa indefinidamente (es un bucle infinito intencionado hasta que acierte; en el Módulo 11 aprenderás a limitar los intentos).

Ejemplo 2: Suma de una lista con for y acumulador.

# archivo: suma.py
notas = [7, 8, 6, 9, 10]
total = 0
for nota in notas:
    total += nota
media = total / len(notas)
print(f"Media: {media:.2f}")

Seguimiento: total empieza en 0 y acumula cada nota. len(notas) es 5. La media es 40 / 5 = 8.0. :.2f formatea con dos decimales.

Ejemplo 3: else en un bucle de búsqueda.

# archivo: buscar.py
nombres = ["Ana", "Luis", "Eva"]
buscado = "Carlos"
 
for nombre in nombres:
    if nombre == buscado:
        print(f"{buscado} está en la lista.")
        break
else:
    print(f"{buscado} no está en la lista.")

Predicción: Como "Carlos" no está, no hay break y se ejecuta el else. Si buscado fuera "Luis", el break evitaría el else.


7. Seguimiento de la ejecución

Cuando Python encuentra un bucle for sobre una secuencia, internamente obtiene un iterador (un objeto que produce elementos uno a uno) y llama a su método next() repetidamente. Cada llamada devuelve el siguiente elemento y lo asigna a la variable del bucle. Cuando no quedan elementos, se lanza una excepción interna StopIteration que el bucle captura y utiliza para terminar. No necesitas gestionar esto manualmente; es la maquinaria que hace funcionar el for. En el Módulo 15 profundizarás en iteradores y generadores.

En un while, el proceso es más simple: se evalúa la condición; si es verdadera, se ejecuta el cuerpo y se vuelve a evaluar; si es falsa, se sale.


8. Errores habituales

ErrorCausaCómo diagnosticarlo
Bucle infinitoLa condición nunca se vuelve falsa.Añade print() de la variable de control dentro del bucle para ver si cambia.
range(5) no incluye el 5El límite superior es exclusivo.Usa range(6) si necesitas llegar a 5.
Contador que no se incrementaOlvidar contador += 1.Revisa que la variable de la condición se modifique dentro del bucle.
break que sale del bucle equivocadoEn bucles anidados, break solo afecta al bucle más interno.Usa una bandera o refactoriza si necesitas salir de varios niveles.
else del bucle que no se ejecutaEl bucle se interrumpió con break.Comprueba si hay un break que se está ejecutando antes de lo esperado.
Modificar una colección mientras se iteraPuede provocar comportamientos impredecibles.Itera sobre una copia (lista.copy()) o crea una nueva colección.
for i in range(len(lista)) para recorrer una listaEs poco idiomático y propenso a errores.Usa for elemento in lista: o, si necesitas el índice, enumerate(lista).
[ERROR HABITUAL] El uso de range(len(lista)) para luego acceder a lista[i] es un patrón heredado de otros lenguajes. En Python, itera directamente sobre los elementos. Si necesitas el índice, enumerate() es la forma idiomática (lo verás con detalle en el Módulo 8, pero puedes usarlo ya: for i, elemento in enumerate(lista):).

9. Particularidades de Python frente a otros lenguajes

- for itera sobre elementos, no sobre índices. En C o Java, el bucle for clásico usa un contador. En Python, for elemento in secuencia: recorre los elementos directamente. Esto es más legible y menos propenso a errores de índice. - range() es un objeto lazy. No crea una lista en memoria; genera los números cuando se necesitan. En otros lenguajes, una función similar podría devolver un array. - Cláusula else en bucles. Característica poco común que permite ejecutar código cuando el bucle termina sin break. No existe en C, Java o JavaScript. - break y continue son palabras clave, no funciones ni etiquetas. En Java, por ejemplo, existen etiquetas para salir de bucles anidados; en Python, no (aunque puedes simularlo con banderas o funciones). - No hay bucle do-while. Python no tiene un bucle que ejecute el cuerpo al menos una vez antes de comprobar la condición. Se puede simular con while True: y un break al final, pero no es idiomático.


10. Buenas prácticas

Incorrecto (poco idiomático y propenso a errores):

lista = [10, 20, 30]
i = 0
while i < len(lista):
    print(lista[i])
    i += 1

Mejor:

lista = [10, 20, 30]
for elemento in lista:
    print(elemento)
[BUENA PRÁCTICA] Itera directamente sobre los elementos cuando no necesites el índice. Si lo necesitas, usa enumerate(). Evita range(len(...)) salvo que tengas una razón muy concreta.
[BUENA PRÁCTICA] Mantén el cuerpo del bucle pequeño y con una responsabilidad clara. Si un bucle ocupa más de 15-20 líneas, considera dividirlo en funciones (Módulo 9) o simplificar la lógica.
[BUENA PRÁCTICA] No modifiques una lista mientras la recorres. Si necesitas eliminar elementos, itera sobre una copia o crea una nueva lista con los elementos que quieres conservar. La documentación oficial advierte explícitamente sobre esto.

11. Windows y Linux

Los bucles son idénticos en Windows y Linux. La sintaxis, el comportamiento de range(), break, continue y else no cambian. La única diferencia operativa relevante es la interrupción de un bucle infinito: Ctrl + C funciona en ambos sistemas.

[WINDOWS / LINUX] Si ejecutas un script con un bucle que imprime muchas líneas, la terminal puede volverse lenta. En ambos sistemas puedes redirigir la salida a un archivo (py script.py > salida.txt en Windows, python3 script.py > salida.txt en Linux) para revisarla después sin sobrecargar la terminal.

12. Ejercicios guiados

Ejercicio guiado 1: Tabla de multiplicar con for.

Escribe un programa que pida un número y muestre su tabla de multiplicar del 1 al 10.

1. Predice cuántas líneas se mostrarán. 2. Usa for i in range(1, 11): y una f-string para el formato. 3. Ejecútalo y comprueba el resultado.

Ejercicio guiado 2: Suma hasta cero con while.

Pide números al usuario y súmalos. El bucle debe terminar cuando el usuario introduzca 0. Muestra la suma total.

1. ¿Qué condición debe tener el while? 2. ¿Dónde se actualiza la variable que controla el bucle? 3. ¿Qué ocurre si el usuario introduce un número negativo?

Ejercicio guiado 3: Búsqueda con else.

Dada la lista [4, 8, 15, 16, 23, 42], pide un número al usuario e indica si está o no en la lista. Usa un for con break y un else para el caso de no encontrarlo.


13. Ejercicios autónomos

1. Predicción: Sin ejecutar, indica qué muestra cada bucle.

  ```python
  for i in range(3):
      print(i)
  ```
  ```python
  x = 3
  while x > 0:
      print(x)
      x -= 1
  ```

2. Contador de vocales: Pide una frase y cuenta cuántas vocales contiene (considera a, e, i, o, u, mayúsculas y minúsculas).

3. Número secreto: Genera un número aleatorio entre 1 y 10 (puedes usar import random; secreto = random.randint(1, 10)) y pide al usuario que lo adivine. El bucle debe repetirse hasta que acierte, indicando si el número introducido es mayor o menor que el secreto.

4. Bucles anidados: Muestra todas las tablas de multiplicar del 1 al 5, cada una separada por una línea en blanco.

5. Reto opcional: Investiga qué hace enumerate() y reescribe este bucle usándolo:

  ```python
  frutas = ["manzana", "pera", "uva"]
  for i in range(len(frutas)):
      print(i, frutas[i])
  ```

14. Soluciones razonadas

Solución al ejercicio guiado 1:

numero = int(input("Introduce un número: "))
for i in range(1, 11):
    print(f"{numero} x {i} = {numero * i}")

range(1, 11) genera los números del 1 al 10. La f-string formatea cada línea.

Solución al ejercicio guiado 2:

suma = 0
numero = int(input("Introduce un número (0 para salir): "))
while numero != 0:
    suma += numero
    numero = int(input("Introduce otro número (0 para salir): "))
print(f"Suma total: {suma}")

La condición es numero != 0. La variable numero se actualiza dentro del bucle con un nuevo input(). Los números negativos se suman igual; si no se desean, habría que añadir una condición (Módulo 6).

Solución al ejercicio guiado 3:

lista = [4, 8, 15, 16, 23, 42]
buscado = int(input("Introduce un número: "))
 
for n in lista:
    if n == buscado:
        print("Encontrado")
        break
else:
    print("No encontrado")

Si buscado está, el break evita el else. Si no está, el for termina sin break y se ejecuta el else.

Solución al ejercicio 1 (predicción):

- Primer bucle: 0, 1, 2. range(3) genera 0, 1 y 2 (el 3 no se incluye). - Segundo bucle: 3, 2, 1. x empieza en 3; se imprime y se decrementa hasta que x > 0 es falso.

Solución al ejercicio 2 (contador de vocales):

frase = input("Introduce una frase: ").lower()
vocales = 0
for letra in frase:
    if letra in "aeiou":
        vocales += 1
print(f"La frase tiene {vocales} vocales.")

.lower() normaliza las mayúsculas. letra in "aeiou" comprueba pertenencia (Módulo 4).

Solución al ejercicio 5 (reto opcional):

frutas = ["manzana", "pera", "uva"]
for i, fruta in enumerate(frutas):
    print(i, fruta)

enumerate() devuelve pares (índice, elemento) en cada iteración, evitando range(len(...)) y el acceso por índice.


15. Resumen

- Un bucle repite instrucciones. while repite mientras una condición sea verdadera; for recorre los elementos de una secuencia. - range() genera progresiones aritméticas; el límite superior es exclusivo. - Un contador cuenta ocurrencias; un acumulador suma valores. Ambos se inicializan antes del bucle. - break sale del bucle inmediatamente; continue salta a la siguiente iteración. - El else de un bucle se ejecuta si el bucle termina sin break; es útil para búsquedas. - Los bucles anidados ejecutan el bucle interno completo por cada iteración del externo. - Un bucle infinito ocurre cuando la condición nunca se vuelve falsa; se detiene con Ctrl + C. - Itera directamente sobre los elementos (for x in lista:) en lugar de usar range(len(lista)). Si necesitas el índice, usa enumerate().


16. Autoevaluación

1. ¿Cuándo usarías while en lugar de for? Pon un ejemplo concreto. 2. ¿Qué diferencia hay entre break y continue? 3. ¿Qué hace el else de un bucle for? ¿Cuándo no se ejecuta? 4. ¿Por qué range(5) genera cinco números y no seis? 5. Reto: Sin ejecutar, predice cuántas veces se ejecuta el print en este código y qué muestra:

  ```python
  for i in range(2):
      for j in range(3):
          print(i, j)
  ```

informatica/programacion/cursos/programacion_desde_cero_con_python/bucles_y_repeticion.txt · Última modificación: por tempwin