Iterando con for en Python, estructura de control definida

El bucle for en Python permite ejecutar un determinado bloque de código un número de veces que viene determinado por la clase iterable que es usada.

Introducción al for

Anteriormente hemos visto otras estructuras de control como el if o el while. A continuación explicaremos el for y sus particularidades en Python, que comparado con otros lenguajes de comparación, tiene ciertas diferencias.

El for es un tipo de bucle, parecido al while pero con ciertas diferencias. La principal diferencia es que el número de iteraciones de un for esta definido de antemano, mientras que en un while no. La diferencia principal con respecto al while es en la condición. Mientras que en el while la condición era evaluada en cada iteración para decidir si volver a ejecutar o no el código, en el for no existe tal condición, sino un iterable que define las veces que se ejecutará el código. En el siguiente ejemplo vemos un bucle for que se ejecuta 5 veces, y donde la i incrementa su valor "automáticamente" en 1 en cada iteración.

for i in range(0, 5):
    print(i) #0,1,2,3,4

Si has leído el capítulo del while, tal vez ya empieces a ver ventajas en el uso del for. Si por ejemplo, queremos tener un número que va creciendo de 0 a n, hacerlo con for nos ahorra alguna línea de código, porque no tenemos que escribir código para incrementar el número.

En Python se puede iterar prácticamente todo, como por ejemplo una cadena. En el siguiente ejemplo vemos como la i va tomando los valores de cada letra. Mas adelante explicaremos que es esto de los iterables e iteradores.

for i in "CursosPython":
    print(i) #C,u,r,s,o,s,P,y,t,h,o,n

Iterables e iteradores

Para entender al cien por cien los bucles for, y como Python fue diseñado como lenguaje de programación, es muy importante entender los conceptos de iterables e iteradores. Empecemos con un par de definiciones:

  • Los iterables son aquellos objetos que como su nombre indica pueden ser iterados, lo que dicho de otra forma es, que puedan ser indexados. Si piensas en un array (o una list en Python), podemos indexarlo con lista[1] por ejemplo, por lo que sería un iterable.
  • Los iteradores son objetos que hacen referencia a un elemento, y que tienen un método next que permite hacer referencia al siguiente.

Para saber más: Si quieres saber más sobre los iteradores te dejamos este enlace a la documentación oficial.

Ambos son conceptos un tanto abstractos y que pueden ser complicados de entender. Veamos unos ejemplos. Como hemos comentado, los iterables son objetos que pueden ser iterados o accedidos con un índice. Algunos ejemplos de iterables en Python son las listas, tuplas, cadenas o diccionarios. Sabiendo esto, lo primero que tenemos que tener claro es que en un for, lo que va después del in deberá ser siempre un iterable.

#for <variable> in <iterable>:
#    <Código>

Tiene bastante sentido, porque si queremos iterar una variable, esta variable debe ser iterable, todo muy lógico. Pero llegados a este punto, tal vez de preguntes ¿pero cómo se yo si algo es iterable o no?. Bien fácil, con la siguiente función isinstance() podemos saberlo. No te preocupes si no entiendes muy bien lo que estamos haciendo, fíjate solo en el resultado, True significa que es iterable y False que no lo es.

from collections import Iterable
lista = [1, 2, 3, 4]
cadena = "CursosPython"
numero = 10
print(isinstance(lista, Iterable))  #True
print(isinstance(cadena, Iterable)) #True
print(isinstance(numero, Iterable)) #False

Por lo tanto las listas y las cadenas son iterables, pero numero, que es un entero no lo es. Es por eso por lo que no podemos hacer lo siguiente, ya que daría un error. De hecho el error sería TypeError: int' object is not iterable.

numero = 10
#for i in numero:
#    print(i)

Una vez entendidos los iterables, veamos los iteradores. Para entender los iteradores, es importante conocer la función iter() en Python. Dicha función puede ser llamada sobre un objeto que sea iterable, y nos devolverá un iterador como se ve en el siguiente ejemplo.

lista = [5, 6, 3, 2]
it = iter(lista)
print(it)       #<list_iterator object at 0x106243828>
print(type(it)) #<class 'list_iterator'>

Vemos que al imprimir it es un iterador, de la clase list_iterator. Esta variable iteradora, hace referencia a la lista original y nos permite acceder a sus elementos con la función next(). Cada vez que llamamos a next() sobre it, nos devuelve el siguiente elemento de la lista original. Por lo tanto, si queremos acceder al elemento 4, tendremos que llamar 4 veces a next(). Nótese que el iterador empieza apuntando fuera de la lista, y no hace referencia al primer elemento hasta que no se llama a next() por primera vez.

lista = [5, 6, 3, 2]
it = iter(lista)
print(next(it))
#     [5, 6, 3, 2]
#      ^
#      |
#     it
print(next(it))
#     [5, 6, 3, 2]
#         ^
#         |
#        it
print(next(it))
#     [5, 6, 3, 2]
#            ^
#            |
#           it

Para saber mas: Existen otros iteradores para diferentes clases:

  • str_iterator para cadenas
  • list_iterator para sets.
  • tuple_iterator para tuplas.
  • set_iterator para sets.
  • dict_keyiterator para diccionarios.

Dado que el iterador hace referencia a nuestra lista, si llamamos más veces a next() que la longitud de la lista, se nos devolverá un error StopIteration. Lamentablemente no existe ninguna opción de volver al elemento anterior.

lista = [5, 6]
it = iter(lista)
print(next(it))
print(next(it))
#print(next(it)) # Error! StopIteration

Es perfectamente posible tener diferentes iteradores para la misma lista, y serán totalmente independientes. Tan solo dependerán de la lista, como es evidente, pero no entre ellos.

lista = [5, 6, 7]
it1 = iter(lista)
it2 = iter(lista)
print(next(it1)) #5
print(next(it1)) #6
print(next(it1)) #7
print(next(it2)) #5

Uso del range

Uno de las iteraciones mas comunes que se realizan, es la de iterar un número entre por ejemplo 0 y n. Si ya programas, estoy seguro de que estas cansado de escribir esto, aunque sea en otro lenguaje. Pongamos que queremos iterar una variable i de 0 a 5. Haciendo uso de lo que hemos visto anteriormente, podríamos hacer lo siguiente.

for i in (0, 1, 2, 3, 4, 5):
    print(i) #0, 1, 2, 3, 4, 5

Se trata de una solución que cumple con nuestro requisito. El contenido después del in se trata de una clase que como ya hemos visto antes, es iterable, y es de hecho una tupla. Sin embargo, hay otras formas de hacer esto en Python, haciendo uso del range().

for i in range(6):
    print(i) #0, 1, 2, 3, 4, 5

El range() genera una secuencia de números que van desde 0 por defecto hasta el número que se pasa como parámetro menos 1. En realidad, se pueden pasar hasta tres parámetros separados por coma, donde el primer es el inicio de la secuencia, el segundo el final y el tercero el salto que se desea entre números. Por defecto se empieza en 0 y el salto es de 1.

#range(inicio, fin, salto)

Por lo tanto, si llamamos a range() con (5,20,2), se generarán números de 5 a 20 de dos en dos. Un truco es que el range() se puede convertir en list.

print(list(range(5, 20, 2)))

Y mezclándolo con el for, podemos hacer lo siguiente.

for i in range(5, 20, 2):
    print(i) #5,7,9,11,13,15,17,19

Se pueden generar también secuencias inversas, empezando por un número mayor y terminando en uno menor, pero para ello el salto deberá ser negativo.

for i in range (5, 0, -1):
    print(i) #5,4,3,2,1

Uso de break y continue

Al igual que en los bucles while, dentro de los for también se puede hacer uso de las sentencias break y continue. Ambas nos permiten cambiar la forma en la que el bucle es ejecutado, bien terminándolo prematuramente, o saltando el bloque de código y pasando a la siguiente iteración.

  • El uso del break permite romper el bucle y salir fuera del mismo. Una vez se encuentra la palabra break, el bucle se habrá terminado.
  • El continue se salta todo el código restante en la iteración actual y vuelve al principio en el caso de que aún queden iteraciones por completar.

En el siguiente ejemplo tenemos un caso poco útil funcionalmente pero útil para entender el comportamiento del break. El range(5) generaría 5 iteraciones, donde la i valdría de 0 a 4. Por lo tanto, el bucle se ejecutaría 5 veces. Sin embargo, justo en la primera iteración tenemos un break. El break hace que nada más empezar el bucle, se rompa y se salga sin haber hecho nada.

for i in range(5):
    break
    print("No llega")

Un ejemplo un poco más útil, sería el de buscar una letra en una palabra. Se itera toda la palabra y en el momento en el que se encuentra la letra que buscábamos, se rompe el bucle y se sale. Esto es algo muy útil porque si ya encontramos lo que estábamos buscando, no tendría mucho sentido seguir iterando la lista, ya que desperdiciaríamos recursos.

cadena = 'CursosPython'
for letra in cadena:
    if letra == 's':
        print("Se encontró la s")
        break
    print(letra)
#C
#u
#r
#Se encontró la s

Por otro lado tenemos el continue. Lo que realiza esta sentencia es, una vez encontrada, se salta todo el bloque de código restante en el for y vuelve al principio otra vez. Por lo tanto la diferencia entre el break y continue es que el continue no rompe el bucle, si no que pasa a la siguiente iteración saltando el código pendiente. En el siguiente ejemplo vemos como al encontrar la letra P se llama al continue, lo que hace que se salte el print(). Es por ello por lo que no vemos la letra P impresa en pantalla.

cadena = 'CursosPython'
for letra in cadena:
    if letra == 'P':
        continue
    print(letra)
#C,u,r,s,o,s,y,t,h,o,n

For anidados

Es posible anidar los for, es decir, meter uno dentro de otro. Esto puede ser muy útil si queremos iterar algún objeto que en cada elemento, tiene a su vez otra clase iterable. Podemos tener por ejemplo, una lista de listas, una especie de matriz.

lista = [[56, 34, 1],
        [12, 4, 5],
        [9, 4, 3]]

Si iteramos usando sólo un for, estaremos realmente accediendo a la segunda lista, pero no a los elementos individuales.

for i in lista:
    print(i)
#[56, 34, 1]
#[12, 4, 5]
#[9, 4, 3]

Si queremos acceder a cada elemento individualmente, podemos anidar dos for. Uno de ellos se encargará de iterar las columnas y el otro las filas.

for i in lista:
    for j in i:
        print(j)
#56,34,1,12,4,5,9,4,3

Ejemplos

Iterando cadena al revés. Haciendo uso de [::-1] se puede iterar la lista desde el último al primer elemento.

texto = "CursosPython"
for i in texto[::-1]:
    print(i) #n,o,h,t,y,P,s,o,s,r,u,C

Itera la cadena saltándose elementos. Con [::2] vamos tomando un elemento si y otro no.

texto = "CursosPython"
for i in texto[::2]:
    print(i) #C,r,o,P,t,o

Un ejemplo de for usado con comprehensions lists. Hablaremos de esto en otros post.

print(sum(i for i in range(10))) # 45

Si quieres saber más sobre estructuras de control, te dejamos otros enlaces que tal vez te interesen también:

¡Deja un comentario!

avatar
  Subscribe  
Notify of