Saltar a contenido

Bucle infinito controlado

Si retomamos el problema de la validación de números positivos, podemos ver que la solución propuesta no es la más adecuada:

python
n = int(input("¿Cuántas veces debe martillar la herramienta? "))
    if n < 0:
        n = int(input("Ups, necesito un número positivo. ¿Cuántas veces debe martillar la herramienta? "))
            if n < 0:
                n = int(input("Ups, necesito un número positivo. ¿Cuántas veces debe martillar la herramienta? "))
                if 

                

En lugar de repetir la pregunta infinitamente a través de estructuras alternativas dentro de otras estructuras alternativas, podemos utilizar un bucle infinito controlado para validar el ingreso de datos.

Paradigma del "bucle infinito"

¿Qué es un bucle infinito? Es simplemente uno que dura para siempre.

Hemos visto anteriormente cómo eso puede suceder de manera accidental desde el punto de vista matemático. Y dijimos que debemos evitarlo a toda costa, así como también vimos de que manera podemos frenarlo en caso de que por un error de la lógica de nuestro código, y a pesar de nuestro esfuerzo por evitarlo, se produzca.

Pero, ¿qué pasa si queremos que un bucle dure para siempre? ¿Es posible? Sí, es posible. Y es algo que se hace deliberadamente en muchos programas.

Por ejemplo, si asumimos que una estructura repetitiva se ejecute sin necesidad de validar una cierta condición, podemos hacer que el bucle se ejecute para siempre.

python
while True:
    # Aquí va el código que se ejecutará infinitamente

En este caso, el bucle while se ejecutará infinitamente, ya que la condición True siempre será verdadera. Así, la respuesta a la pregunta "verdadero" siempre es "verdadero".

Esta es una manera de inducir deliberadamente un bucle que, por defecto, durará para siempre. Y como dijimos, esto no debe hacerse a menos que sea absolutamente necesario.

Y entonces, ¿cómo nos beneficiamos de este paradigma para resolver el problema de la validación de números positivos, en nuestro ejemplo, y de la validación del ingreso de datos en general?

¿Qué es un bucle infinito controlado?

Un bucle infinito controlado es un bucle que dura para siempre, como el ejemplo anterior, pero que se detiene en algún momento específico. También se lo conoce como bucle centinela o loop controlado por condición indefinida.

En este enfoque, el ciclo se inicia con la suposición de que continuará indefinidamente a partir de la instrucción while True:, pero se incluye una condición o lógica interna que rompe el bucle cuando se cumplen ciertos criterios.

¡Para recordar!

Este patrón es común en Python y otros lenguajes, y se utiliza especialmente cuando no se puede determinar de antemano cuántas veces debe repetirse el ciclo, hasta que se obtenga la entrada o el resultado deseado.

¿Cómo se detiene? A través de una instrucción de salida explícita.

Para entenderlo mejor, en Python funciona así:

  1. Primero, decimos while True:. Esto es como decir "Vamos a seguir preguntando hasta que obtengamos la respuesta que necesitamos".
  2. Dentro de este bucle, pedimos la información que necesitamos.
  3. Luego, revisamos si la información es correcta (en nuestro ejemplo, si el número es positivo).
  4. Si es correcta, usamos una instrucción de salida explícita para salir del bucle. Es como decir "¡Genial! Obtuve lo que quería, puedo parar de preguntar".
  5. Si no es correcta, el bucle continúa, se repite y volvemos a pedir la información nuevamente.

Este método es muy útil porque nos permite seguir pidiendo información hasta que obtengamos exactamente lo que necesitamos, sin tener que escribir el mismo código una y otra vez.

Analicemos cómo podemos aplicar este enfoque al problema de la validación de números positivos.

continue y break

Podemos utilizar las instrucciones continue y break para controlar un bucle infinito, convertirlo en un bucle infinito controlado y resolver el problema de la validación de números positivos.

python
1
2
3
4
5
6
7
8
9
while True:
    n = int(input("¿Cuántas veces debe martillar la herramienta? "))
    if n < 0:
        print("Ups, necesito un número positivo.")
        continue
   else:
        break

print(f"El operador martillará la herramienta {n} veces.")

Al ejecutar nuestro programa, el bucle while True se ejecutará infinitamente hasta que el usuario ingrese un número positivo.

Terminal (Entrada/Salida)
¿Cuántas veces debe martillar la herramienta? -5
Ups, necesito un número positivo.
¿Cuántas veces debe martillar la herramienta? -3
Ups, necesito un número positivo.
¿Cuántas veces debe martillar la herramienta? 10
El operador martillará la herramienta 10 veces.

En este caso, si el usuario ingresa un número negativo, el programa imprimirá un mensaje de error y continuará con la siguiente iteración del bucle. Es decir que el flujo del programa, al ejecutar la instrucción continue, vuelve al principio del bucle, como la condición es True, se vuelve a ingresar en el bucle y el usuario puede ingresar un nuevo número.

Si el usuario ingresa un número positivo, el programa, al ejecutar la instrucción break, saldrá del bucle y continuará con el resto del programa.

Optimizando el código

Luego de analizar el funcionamiento de nuestro programa:

python
1
2
3
4
5
6
7
8
9
while True:
    n = int(input("¿Cuántas veces debe martillar la herramienta? "))
    if n < 0:
        print("Ups, necesito un número positivo.")
        continue
   else:
        break

print(f"El operador martillará la herramienta {n} veces.")

Podemos optimizar nuestro código para que sea más legible y eficiente. Si bien es cierto que la instrucción continue es útil para controlar el flujo del programa, permitiendo finalizar la ejecución del bloque de código repetitivo actual sin importar finalizar con todas las instrucciones, volviendo a validar la condición y, en caso afirmativo, repetir una nueva ejecución del bucle; en este caso dicho bloque de código no posee instrucciones posteriores a la estructura if n < 0: que requieran de una finalización de ejecución abrupta para evitar su procesamiento.

Por lo tanto, podemos simplificar nuestro código eliminando la instrucción continue y reemplazando la estructura if n < 0: por una estructura if n > 0: (asumimos que algún clavo se deberá clavar) que permita la ejecución de las instrucciones posteriores a la validación de la condición.

python
1
2
3
4
5
6
7
8
while True:
    n = int(input("¿Cuántas veces debe martillar la herramienta? "))
    if n > 0:
        break

    print("Ups, necesito un número positivo.")

print(f"El operador martillará la herramienta {n} veces.")

Aquí es importante recalcar que al validar n > 0 y ejecutar la instrucción break, el flujo del programa saldrá del bucle y continuará con el resto del programa, evitando la ejecución de las instrucciones posteriores a la estructura if n < 0:.

Por lo tanto, la instrucción continue no es necesaria en este caso.

Y tampoco es necesario implementar else puesto que si la condición n > 0 no se cumple, el flujo del programa continuará con la ejecución de la instrucción print("Ups, necesito un número positivo."), pasando por alto la ejecución de las instrucciones posteriores a la estructura if n < 0:, en este caso, la instrucción break.

¡Para recordar!

Puedes utilizar un bucle infinito controlado para validar la entrada del usuario hasta que se cumpla una condición específica.

Este enfoque es común en Python y otros lenguajes de programación cuando se necesita asegurar que la entrada del usuario cumpla ciertos criterios.

  • Se utiliza un bucle while True para crear un bucle infinito.
  • Dentro del bucle, se solicita la entrada del usuario.
  • Se verifica si la entrada cumple con la condición deseada.
  • Si la condición se cumple, se utiliza break para salir del bucle.
  • Si la condición no se cumple, el bucle continúa y se vuelve a solicitar la entrada.

break vs. return dentro de funciones

Existe un caso particular que se puede presentar al combinar funciones con bucles. Cuando hablamos de funciones nos referimos a las funciones que nosotros podemos definir y utilizar en nuestros programas.

Es importante tener en cuenta la diferencia entre break y return en Python.

  • break se utiliza para salir de un bucle, como en el ejemplo anterior.
  • return se utiliza para devolver un valor de una función y finalizar su ejecución.

En general, no se recomienda utilizar return dentro de un bucle, ya que puede causar problemas de legibilidad y mantenimiento.

Sin embargo, si combinamos funciones con bucles, podemos utilizar return para salir de un bucle y una función al mismo tiempo. Veamos un ejemplo.

Crearemos la función main() que contendrá las dos tareas principales de nuestro programa; y a su vez crearemos dos funciones que contendrán la lógica de ejecución de cada una de estas tareas específicas: solicitar_cantidad_de_martillazos() e imprimir_cantidad_de_martillazos():

python
def main():
    n = solicitar_cantidad_de_martillazos()
    imprimir_cantidad_de_martillazos(n)

def solicitar_cantidad_de_martillazos():
    while True:
        n = int(input("¿Cuántas veces debe martillar la herramienta? "))
        if n > 0:
            return n # Salir del bucle y devolver el valor

        print("Ups, necesito un número positivo.")

def imprimir_cantidad_de_martillazos(n):
    print(f"El operador martillará la herramienta {n} veces.")

main()

En este caso, la función solicitar_cantidad_de_martillazos() se encarga de solicitar la cantidad de martillazos al usuario y validar que sea un número positivo. Si la cantidad es positiva, la función devuelve el valor y finaliza su ejecución, sin necesidad de ejecutar break dentro de la estructura del bucle.

Si bien es cierto que en este caso la instrucción return es válida, es importante tener en cuenta que su uso dentro de un bucle puede resultar en una estructura de código menos legible y más difícil de mantener.

Por lo tanto, se recomienda utilizar break para salir de un bucle y return para devolver un valor de una función:

python
def main():
    n = solicitar_cantidad_de_martillazos()
    imprimir_cantidad_de_martillazos(n)

def solicitar_cantidad_de_martillazos():
    while True:
        n = int(input("¿Cuántas veces debe martillar la herramienta? "))
        if n > 0:
            break # Salir del bucle

        print("Ups, necesito un número positivo.")

    return n # Devolver el valor

def imprimir_cantidad_de_martillazos(n):
    print(f"El operador martillará la herramienta {n} veces.")

main()

En este caso, la instrucción break se utiliza para salir del bucle, y return se utiliza para devolver el valor de la función solicitar_cantidad_de_martillazos().

Ventajas del paradigma

  • Simplicidad: Es fácil de entender y de implementar.
  • Eficiencia: Evita la repetición de código innecesario.
  • Flexibilidad: Puede adaptarse a diferentes tipos de validación de entrada.

Desventajas del paradigma

  • Potencial de Bucle Infinito: Si no se maneja correctamente, puede resultar en un bucle infinito que nunca termina.
  • Legibilidad: Aunque es un enfoque común, algunos desarrolladores pueden encontrarlo menos legible o intuitivo.

Conclusión

El uso de un bucle infinito controlado es un paradigma común y efectivo en Python para validar la entrada del usuario hasta que se cumpla una condición específica.

Este enfoque asegura que el programa no procederá hasta que se reciba una entrada válida, mejorando la robustez y la fiabilidad del código.