domingo, 27 de octubre de 2024

Lenguajes. Python.

Iteración. Bucles.

Literación no es otra cosa que la ejecución de una instrucción de forma repetida. Junto con  la sucesión lineal y la bifurcación condicional, la iteración es una de las formas que pueden presentar el desarrollo de un algoritmo. Los bucles son las instrucciones (o estructuras instruccionales) que concretan cómo hacerlo y la potencia de procesamiento de los ordenadores la que permite que se realice de forma rápida y eficiente.


Mediante los bucles podemos recorrer amplios conjunto de datos para encontrar los que deseemos, también podemos crear respuestas sucesivas en función de determinadas condiciones. En cualquier caso estamos hablando de dos cuestiones que se alejan del carácter básico que tiene como objetivo esta entrada (1), en la que me limitaré a exponer las estructuras de iteración.

El lenguaje Python cuenta con dos estructuras de iteración o bucles: el bucle for y el bucle while, que permiten dos formas diferentes de iteración (2): una (for, "para") mediante un iterador y la otra (while, "mientras") en función del cumplimiento de una condición. En esta entrada mostraré la forma básica de uso de ambos, dejando para posteriores una explicación más detallada de las mismas.

El bucle for cuenta con una variable, un objeto iterable y un bloque de código. Un iterable no es otra cosa que un conjunto de valores que va tomando la variable en cada paso de la ejecución del bucle. Son muchos los objetos iterables en Python, además de los que podemos construir nosotros (3).

Una forma básica de crear un iterable en Python es la siguiente...

for n in (1,2,3,4,5):

    print("El valor de n es",n) 

La variable n adopta sucesivamente los valores indicados en el iterable (1,2,3,4,5) al que se referencia (n in (1,2,3,4,5)). Todo ello se muestra (visualiza) gracias a la instrucción o bloque de código subordinado que sigue ( print("El valor de n es",n) ) y que es lo siguiente:

El valor de n es 1
El valor de n es 2
El valor de n es 3
El valor de n es 4
El valor de n es 5

Otra forma de expresar un bucle for es la siguiente (4):

num = 5

for n  in range(1,11):

    print(n,"x",num,'=',n*num) 

... que nos devuelve:

1 x 5 = 5
2 x 5 = 10
3 x 5 = 15
4 x 5 = 20
5 x 5 = 25
6 x 5 = 30
7 x 5 = 35
8 x 5 = 40
9 x 5 = 45
10 x 5 = 50

La función range() cuenta con tres parámetros o valores: el inicial, el final y el de incremento (opcional). Mediante range(1,11) obtenemos un objeto iterable formado por los valores 1, 2, 3, 4, 5, 6, 7, 8, 9 y 10, que son los que necesitamos para crear la tabla de num (en nuestro caso, del 5). Observa que si hiciéramos algo parecido mediante la primera formulación no obtendríamos ese resultado, ya que no se utiliza el valor num, únicamente se itera por los posibles valores de (5). La función range() simplifica la expresión del iterable, haciendo innecesaria la enumeración de sus contenidos concretos y permitiendo establecer series de mayor complejidad (mediante el valor de incremento)

Una tercera forma de iterar es partiendo de un objeto iterable previamente definido y utilizarlo en el bucle como tal (como iterable) que recorremos mediante una variable. Un ejemplo (6)...

dias = ['lunes','martes','miércoles','jueves']

for dia in dias:
    print(dia)

... que nos devuelve

lunes

martes

miércoles

jueves

El bucle while tiene otra lógica de funcionamiento, ya que se basa en el cumplimiento de una condición que previamente se debe establecer (7) y que es previsible que se modifique a lo largo del recorrido del bucle (8). Además de las instrucciones que se desarrollen en su interior, while puede contener una instrucción o cláusula else, cuya función es establecer las instrucciones que se cumplirán cuando la condición deje de ser V. Esta cláusula es opcional.

Veamos un ejemplo de bucle while:

num = 0

while num < 10:
    print (num)
    num = num + 1 
else:
    print ("Has llegado a la meta") 

En este script establecemos un valor de inicio para la variable num (num = 0), lo que permite que el el bucle se inicie sin generar error. A continuación establecemos la condición del bucle (while num < 10), esto es: este bucle se ejecutará mientras la condición num < 10 sea True. Mientras esa condición se cumpla, el bucle nos devolverá como salida la escritura del valor que toma num (esto es, se cumple la instrucción que contiene:  print (num)).

Para evitar un bucle infinito, en este caso hemos optado por incorporar una instrucción de tipo contador (num = num + 1) que modifica el contenido de la variable, con lo que, en un momento determinado, la condición de partida dejará de ser True para pasar a False. En ese momento entra en funcionamiento la cláusula else, por lo que la salida final de bucle será el contenido de la instrucción asociada a else (print ("Has llegado a la meta")).

Otra forma muy común de trabajar con el bucle while consiste en establecer una variable de control del bucle con valor inicial True, que será la condición de ejecución del propio bucle. Dentro del bucle realizaremos alguna comprobación con un condicional que servirá para modificar el valor de la variable de control y finalizar la ejecución del bucle, al dejar de cumplirse la condición en que se basa.

print('Escribe un número par') # Un número impar servirá para terminar el bucle
seguir=True
while seguir:
    numero=input('Número: ')
    numero=eval(numero)
    if numero%2==1:
        seguir=False
else:
    print('Ha finalizado el bucle.', numero, 'es impar')

En este caso, el cambio de la condición (que quedó definida expresa y previamente en la variable booleana seguir) es el resultado del cumplimiento de una condición establecida dentro del bucle mediante una estructura condicional (if numero%2==1) coherente con el contenido del bucle (las instrucciones que desarrolla ( numero=input('Número: ') -> numero=eval(numero)). Nótese que la instrucción else pertenece al bucle while, no al condicional if (9)

Son muchas las cosas que tenemos que aprender sobre los bucles y sus usos, pero de momento disponemos ya del conocimiento suficiente para integrarlos en sencillos script de aprendizaje, alguno de ellos, incluso, con cierta funcionalidad práctica; aunque esta no sea, por el momento, nuestro objetivo.
NOTAS

(1) Lo expresado remite a las colecciones de datos (matrices) y al uso combinado de bucles y condicionales, temas que se abordarán más adelante.
(2) Tema este también de suficiente complejidad como para requerir un abordaje específico que no corresponde realizar ahora.
(3) Me refiero a las listas, las cadenas de texto, las tuplas... Sobre todas ellas, como iterables, hablaremos en su momento, aunque, por motivos didácticos, utilizaremos ahora algunas de ellas en la ejemplificación del funcionamiento de la iteración. 
(4) Código básico de la tabla de multiplicar del 5.
(5) En el segundo ejemplo, esa iteración de n por el range() queda expresada en el primer valor de lo que devuelve print(). Para replicar el mismo objetivo deberíamos crear el siguiente script:
num = 4
for n in (1,2,3,4,5,6,7,8,9,10):
    print (n,'x',num,'=',n*num)
(6) Que supera los objetivos de esta entrada y que explicaremos en otro momento.
(7) Esta condición determina el desarrollo del bucle, ya que éste sucede mientras se mantenga la condición original, esto es, hasta que esta deje de ser True (V).
(8) En caso contrario daría lugar a un bucle infinito, situación que, obviamente, deberemos evitar.
(9) En función del nivel de sangrado o indentación, que la ubica a la altura de while, no de if. En caso de encontrarse a la altura de if pertenecería a ese condicional y no al bucle. Véase la importancia de la indentación en Python y de lo necesario que es ejecutarla correctamente.