Bucle for en Python: comprender y utilizar de forma adecuada el bucle for
El for loop en Python, en español “bucle for en Python”, se utiliza para ejecutar repetidamente un bloque de código. Los bucles for son una parte fundamental de la mayoría de los lenguajes de programación. A continuación, te mostramos cómo funciona y cómo se utiliza el bucle for en Python.
- Certificado SSL Wildcard
- Registro privado
- 1 cuenta de correo electrónico por contrato
¿Qué es el bucle for en Python?
Junto a la rama if else, el bucle for es probablemente la estructura de programación más conocida. Generaciones de estudiantes se han exprimido el cerebro con el concepto informático del bucle. Esto se debe a que, para empezar, los bucles no son muy intuitivos. Sin embargo, los problemas de interpretación pueden surgir más bien de la forma en la que se presenta el material. Porque, si los analizamos desde un punto de vista general, los bucles no son nada fuera de lo común.
Vamos a explicar el concepto de bucle con un ejemplo ilustrativo. Imaginemos una clase de colegio. El profesor quiere determinar la altura media de los niños como parte de un experimento. Para ello, el profesor pregunta a cada niño su altura, uno por uno, y suma las tallas individuales para obtener un total. A continuación, divide la suma entre el número de niños para obtener la altura media. Extraemos un sencillo algoritmo del procedimiento que ha seguido el profesor:
- Preguntar la altura a cada niño y sumarla de forma consecutiva hasta obtener un total
- Dividir la suma entre el número de niños total
El primer paso se realiza una vez por cada niño y, por tanto, depende del tamaño de la clase. El segundo paso se ejecuta una sola vez, independientemente del tamaño de la clase. Necesitamos un bucle para llevar a cabo el primer paso. A continuación, te mostramos un ejemplo de código que calcula el tamaño medio de un alumno con un bucle for en Python:
children_heights = [155, 171, 148, 161, 158, 153, 162]
height_sum = 0
for height in children_heights:
height_sum = height_sum + height
average_height = height_sum // len(children_heights)
print(average_height)
El bucle for en Python ejecuta un bloque de código de forma repetitiva, lo que también se puede denominar “iteración”. En particular, los bucles permiten que varios elementos combinados en una misma “colección” sean procesados individualmente según un mismo esquema. Utilizamos un bucle for cuando el tamaño de la colección puede determinarse en el momento de ejecutar el programa. Si no es el caso, se suele utilizar un bucle while.
En otro artículo de nuestra guía digital, podrás aprender Python por tu cuenta.
¿Qué diferencia al bucle for en Python de otros lenguajes?
Muchos lenguajes de programación conocen el concepto de bucle for. Además de Python, el bucle for también es una estructura básica en otros lenguajes como C, Java, JavaScript y PHP. Los lenguajes funcionales, como Haskell o Lisp, suelen arriesgarse a no tener un bucle for de manera explícita. En lugar de iterar, estos lenguajes utilizan funciones recursivas.
Todos los bucles tienen en común que un bloque de código se ejecuta repetidamente. Sin embargo, el mecanismo de funcionamiento del bucle for en Python difiere significativamente del de otros lenguajes. La mayoría de los lenguajes de programación utilizan una variable de bucle que se incrementa o disminuye cuando se ejecuta el bucle.
Operación | Significado | Sintaxis convencional | Sintaxis de Python |
---|---|---|---|
Incremento | Aumenta el valor de una variable entera en una cantidad específica y fija. | i++ | index += 1 |
Disminución | Disminuye el valor de una variable entera en una cantidad específica y fija. | i-- | index -= 1 |
Veamos un ejemplo de cómo funciona un bucle for en otros lenguajes de código: produzcamos los números del 0 al 9 en JavaScript con un bucle for. Solo debemos definir una variable entera llamada 'number' e incrementarla siempre que el número que contenga sea menor que 10. El código utilizado para ello parece bastante críptico para los principiantes:
for ( let number = 0; number < 10; number++ ) {
console.log(number);
}
El código respectivo de un bucle for en Python parece mucho más ordenado:
for number in range(10):
print(number)
En lugar de emitir directamente el valor de la variable del bucle, en la práctica este se suele utilizar para indexar un elemento dentro de una colección. De nuevo, empecemos primero con un ejemplo en JavaScript: se emiten los nombres contenidos en la lista “personas” uno tras otro. Aquí utilizamos la variable de bucle 'i' como índice continuo de los elementos individuales:
people = ['Jack', 'Jim', 'John']
for (let i = 0; i < people.length; i++) {
console.log("Here comes " + people[i]);
}
La indexación directa de elementos sucesivos de la lista debe tratarse con precaución. Esto se debe a que un intento de acceso fuera de los límites permitidos conduce a un error en el momento de la ejecución. Por lo general, se trata del famoso “Off-by-one Error”. Python, en cambio, demuestra que también se puede hacer de otra manera. Aquí tenemos el mismo ejemplo con un bucle for en Python: iteramos directamente sobre los elementos de la lista con una variable de bucle sin indexarlos:
people = ['Jack', 'Jim', 'John']
for person in people:
print(f"Here comes {person}")
El uso indirecto de la variable de bucle contribuye mucho a confundir el aprendizaje de los bucles for en otros lenguajes. Esto se debe a que, por lo general, no nos interesa la variable del bucle que se encuentra en su interior. Principalmente, porque solo se utiliza para indexar los elementos individuales. Para utilizar los bucles for convencionales es necesario comprender varios aspectos complejos. Utilizando JavaScript como ejemplo:
Asunto | Ocurrencia en el bucle for de JavaScript |
---|---|
Asignación de variables | let i = 0 |
Expresiones booleanas | i < limit |
Operador de incremento/disminución | i++ / i-- |
Determinar el tamaño de una colección | i < list.length |
Indexación de elementos a cero | i < list.length ist OK; i <= list.length führt zu Off-by-one Error |
El bucle for de Python es mucho más fácil de usar. Aunque se utiliza la misma palabra clave “for”, se trata de un enfoque radicalmente diferente. En lugar de incrementar una variable de bucle y así indexar sucesivamente los elementos, iteramos directamente sobre los elementos de una colección. El bucle for en Python es, por tanto, comparable a la estructura forEach de algunos lenguajes como Ruby y JavaScript.
Vamos a emitir las letras individuales de una palabra a modo de ilustración. Dentro del bucle for, una letra de la palabra se pone a disposición de la variable 'letter' por cada pasada del bucle. Esto funciona sin una variable de bucle y, por lo tanto, sin el riesgo de producir un Off-by-one Error. El código es preciso y fácil de leer:
word = "Python"
for letter in word:
print(letter)
¿Cómo funciona un bucle for en Python?
Como hemos visto, el bucle for en Python resuelve de forma elegante el problema de iterar sobre los elementos de una colección. Nos permite hacerlo sin los desvíos que implica una variable de bucle numérica. Eso está muy bien, pero ¿cómo funciona exactamente? Para entender el principio de funcionamiento del bucle for en Python, primero es necesario conocer los conceptos de iterable e iterador.
¿Qué es el iterable, el iterador y el generador?
El bucle for en Python opera sobre objetos conocidos como “iterables”. Se trata de strings, listas, tuplas y otros tipos de datos compuestos. En palabras de los documentos oficiales de Python:
“[An iterable is] an object capable of returning its members one at a time” - Fuente: https://docs.python.org/3/glossary.html#term-iterable
Traducción: “[Un iterable es] un objeto capaz de retornar sus miembros de uno en uno” (traducido por IONOS)
Un objeto iterable tiene dos propiedades:
- Combina varios elementos en una colección.
- Permite el acceso a los elementos a través de una interfaz llamada “iterador”.
En conjunto, esto significa que los iterables son colecciones cuyo contenido puede ser iterado. En concreto, un iterable tiene un método '__iter__()' que devuelve un iterador. El iterador es un objeto que, con el debido comando, retorna el siguiente elemento del iterable. Además, un iterador recuerda la posición del último elemento devuelto dentro de la colección.
Función | Explicación | Ejemplo |
---|---|---|
iter(collection) | Llama al método __iter__() de la colección | it = iter("Python") |
next(iter) | Llama al método __next__() del iterator | next(it) |
collection[index] | Llama al método __getitem__(index) de la colección | 'Python'[1] |
Un iterador retorna el siguiente elemento cuando se llama al método __next__(). Si se han entregado todos los elementos de la colección, el iterador se agota. Otra llamada a __next__() genera una excepción 'StopIteration'.
Veamos el funcionamiento de un iterador a través de un ejemplo. Creamos un objeto range() que representa los números consecutivos del 21 al 23. Posteriormente, creamos un iterador con la función iter() y emitimos sucesivamente elementos con la función next(). Con la última llamada, se lanza la excepción puesto que el iterador se ha agotado:
numbers = range(21, 24)
number = iter(numbers)
next(number)
# returns `21`
next(number)
# returns `22`
next(number)
# returns `23`
next(number)
# raises `StopIteration` exception
Un iterador permite acceder a elementos individuales de una colección. Python también conoce un concepto semejante conocido como “generador”. La diferencia es que un generador crea elementos individuales solo cuando se accede a ellos. Esto ahorra espacio de memoria durante la ejecución del programa; también se denomina “lazy generation”.
Un generador en Python se basa en una función que utiliza la sentencia yield. Al igual que la sentencia return, devuelve un objeto y finaliza la función. Sin embargo, cuando se activa nuevamente, la función generador no empieza desde el principio, sino que continúa a partir de la última sentencia yield.
Veamos un ejemplo: redactemos nuestra propia implementación de la función range(). Utilizamos, para ello, la sentencia yield dentro de un bucle while para generar números continuos:
def my_range(start, stop):
if stop < start:
return None
current = start
while current < stop:
yield current
current += 1
# test
assert list(my_range(7, 9)) == list(range(7, 9))
Saltar y cancelar la ejecución del bucle for en Python
En la práctica, a veces es necesario saltarse una sola pasada de bucle. Como muchos otros lenguajes, Python dispone de la sentencia continue. Cuando se ejecuta un continue dentro del cuerpo del bucle, se aborta la iteración actual e inicia inmediatamente la siguiente iteración.
Una sentencia continue puede utilizarse de forma similar al early return mientas se ejecuta una función. Por ejemplo, después de determinar que un conjunto de datos no tienes la calidad requerida, vamos a saltarnos una iteración:
def process_data(data):
for data_set in data:
data_set.validate()
# early continue after cheap check fails
if not data_set.quality_ok():
continue
# expensive operation guarded by early continue
data_set.process()
Otro ejemplo: emitimos un texto y saltamos cada dos letras:
text = 'Skipping every second letter'
for index, letter in enumerate(text):
if index % 2 != 0 and letter != ' ':
continue
print(letter)
Además de la sentencia continue para saltarse una pasada del bucle, también existe la sentencia break. Ejecutar un break dentro del cuerpo del bucle aborta inmediatamente la ejecución de este. Así pues, la sentencia break tiene una función en los bucles parecida a la de la sentencia return en las funciones.
La sentencia break se utiliza a menudo para implementar algoritmos de búsqueda. Una vez que se haya encontrado el elemento respectivo dentro de un bucle, no es necesario seguir iterando. De forma análoga a la función any(), comprobamos la presencia de un único valor true en la lista y, en cuanto encontramos algo, rompemos el proceso con la sentencia break:
bool_list = [False, False, True, False]
for index, boolean in enumerate(bool_list):
if boolean:
print(f"Value at position {index + 1} is True")
print(f"Aborting inspection of remaining {len(bool_list) - index - 1} item(s)")
break
En relación con la sentencia break, un bucle for en Python puede estar provisto de una sentencia else opcional. El código que contiene se ejecuta cuando el bucle termina sin que se haya ejecutado una sentencia break:
def find_element(target, collection):
for element in collection:
if element == target:
print("Found what you're looking for")
break
else:
print("Didn't find what you were looking for")
# test
find_element('a', 'Python')
find_element('o', 'Python')
Los bucles for se utilizan a menudo en Python dentro de los cuerpos de las funciones. En este caso, es habitual utilizar una sentencia return en lugar de un break. Volvemos a formular nuestro algoritmo de búsqueda sin el uso de break y else:
def find_element(target, collection):
for element in collection:
if element == target:
print("Found what you're looking for")
# returning breaks us out of the loop
return element
# we made it here without returning
print("Didn't find what you were looking for")
return None
# test
print(find_element('a', 'Python'))
print(find_element('o', 'Python'))
¿Cuáles son las mejores prácticas para los bucles for en Python?
Los bucles for en Python se utilizan principalmente para iterar sobre los elementos de una secuencia o colección. Además, existen métodos más directos para muchos casos de uso común. A continuación, presentamos las mejores prácticas y los antipatrones más importantes. En primer lugar, un resumen de los principales términos:
Término | Explicación | Ejemplo |
---|---|---|
Colección | Colección de varios elementos. Una colección es un iterable | ('Walter', 'White'), [4, 2, 6, 9], 'Python' |
Iterador | Interfaz para iterar sobre colecciones | it = iter('Python') |
Generador | Una función que utiliza la sentencia yield en lugar de return. Un generador es un iterable | range(10) |
Comprensión | Expresión de iteración; crea una nueva colección basada en un iterable | [num ** 2 for num in range(10)] |
Iterar directamente sobre los elementos de una colección
Un error común que cometen los programadores de Python sin experiencia es el mal uso del bucle for en Python. Como es común en otros lenguajes, utilizan la función len() como límite de la función range() para crear una variable numérica de bucle. La utilizan para indexar los elementos individuales de la colección:
word = 'Python'
for i in range(len(word)):
print(word[i])
Este antipatrón se critica con razón por no ser compatible con Python y es mejor iterar directamente sobre los elementos de la colección mediante el bucle for de Python:
word = 'Python'
for letter in word:
print(letter)
Enumerar elementos de una colección con enumerate() incluido el índice
A veces se necesita el índice de un elemento dentro de la colección. En lugar de crear el índice como una variable de bucle, utilizamos la función enumerate(). Esta devuelve la tupla (índice, elemento), aunque debes tener en cuenta que el índice empieza a contar desde cero:
names = ["Jim", "Jack", "John"]
for index, name in enumerate(names):
print(f"{index + 1}. {name}")
Iterar sobre tuplas de elementos con la función zip()
Otro escenario común es iterar sobre los elementos de dos colecciones de igual longitud al mismo tiempo. El enfoque de Python utiliza la función zip(). Toma dos colecciones de igual longitud y devuelve 2 tuplas sucesivas:
people = ('Jim', 'Jack', 'John')
ages = (42, 69, 13)
# ascertain both collections are same length
assert len(people) == len(ages)
# iterate over tuples of (person, age)
for person, age in zip(people, ages):
print(f"{person} is {age} years old")
Crear una variable de bucle numérica con la función range()
Normalmente, los bucles for en Python se utilizan para iterar sobre los elementos de una colección. Utilizar un bucle for en Python para incrementar un número entero es algo poco usual. La mejor manera de hacerlo es construyendo un objeto range con la función range() e iterar sobre él:
for counter in range(10):
print(counter)
Uso del operador in para comprobar si una colección contiene un elemento
Encontrar un elemento específico dentro de una colección forma parte del repertorio estándar de un programador. Normalmente, se utiliza una función que itera sobre los elementos, comprobando la semejanza de cada elemento con el que se busca. Si se encuentra el elemento deseado, se aborta la iteración.
En Python, el operador in existe para este caso tan habitual. Este operador comprueba si la colección contiene el elemento buscado y devuelve el valor booleano correspondiente:
'a' in 'Python'
'y' in 'Python'
Crear una lista a partir de un iterable con la función list()
A diferencia de muchos otros lenguajes, en Python no es necesario utilizar un bucle for para escribir las letras de un string una a una en una lista. En su lugar, utilizamos la función list() para convertir un iterable en una lista de elementos. Veamos ambos enfoques con un ejemplo. Iteramos sobre las letras de una palabra y las añadimos a una lista vacía:
word = 'Python'
letters = []
for letter in word:
letters.append(letter)
apacheconfPodemos ahorrarnos el esfuerzo. Creamos la lista directamente con la función list(). Al mismo tiempo, comprobamos con la sentencia assert que ambos métodos dan el mismo resultado:
assert list(word) == letters
apacheconfOtro ejemplo: creamos una lista de números del cero al nueve y un objeto range sirve de base como iterable:
list(range(10))
apacheconfAdemás de las listas, también se pueden crear conjuntos o “sets” (en inglés) a partir de un iterable. Por ejemplo, creamos un conjunto que refleja las letras contenidas en una frase. A continuación, comprobamos con el operador in que el conjunto de letras no contiene la 'a':
alphabet = set('Python is not hyped')
assert 'a' not in alphabet
apacheconfSustituir los bucles for en Python por comprensiones
Un uso común de los bucles for en Python es el de modificar los elementos de una colección. Se puede utilizar cuando queremos calcular nuevos valores en base a una colección o filtrar ciertos elementos según un patrón. Siguiendo el estilo de programación imperativa, describimos los pasos individuales:
- Iterar sobre la colección con el bucle for.
- Procesar cada elemento.
- Si es necesario, combinar un subconjunto de elementos en una nueva colección.
Para realizar modificaciones sencillas, esto resulta demasiado complejo. Los lenguajes funcionales demuestran que se puede hacer de forma más fácil. Afortunadamente, Python cuenta con el concepto de “comprehensions” (comprensiones). Las comprensiones pueden reemplazar aplicaciones simples del bucle for en Python y, de hecho, son más eficaces que las aplicaciones equivalentes de un bucle for.
Una comprensión crea una colección, que puede estar adaptada y basada en un iterable en caso de que sea necesario. Esta utiliza una sintaxis concisa y expresiva. A continuación, un ejemplo de la sintaxis general de la comprensión de una lista, donde la expresión está escrita entre corchetes y la operación se realiza sobre los elementos de una colección; cada elemento se copia en una nueva lista:
[ operation(element) for element in collection ]
apacheconfAdemás, los elementos pueden filtrarse según determinados patrones. Se utiliza un if opcional y una condición:
[ operation(element) for element in collection if condition(element) ]
apacheconfVeamos ahora un ejemplo de bucle for en Python que se puede sustituir por una comprensión. Tenemos una lista de números y queremos calcular una lista equivalente con los cuadrados de los números de la primera lista:
numbers = [2, 3, 5, 9, 17]
apacheconfCreamos una lista vacía e introducimos un bucle if que contiene el cálculo de los cuadrados de los números en su interior:
squares = []
for number in numbers:
squares.append(number ** 2)
apacheconfLa lista de números cuadrados puede expresarse de forma más sencilla en forma de una lista de comprensión:
squares_comp = [number ** 2 for number in numbers]
apacheconfA continuación, utilizamos la sentencia assert para asegurarnos de que ambos métodos arrojan el mismo resultado:
assert squares == squares_comp
apacheconfOtro ejemplo: si queremos extraer las letras minúsculas de un string, debemos crear e introducir como entrada una lista con una combinación de letras mayúsculas y minúsculas:
word = list("PyThoN")
apacheconfLa forma convencional de extraer las minúsculas es iterar sobre las letras. Durante ese proceso probamos cada letra con la función islower() y, en caso de tener un resultado positivo, las añadimos a una lista inicialmente vacía:
lowers = []
for letter in word:
if letter.islower():
lowers.append(letter)
apacheconfEl bucle for nos lo podemos ahorrar con Python. En su lugar, utilizamos una comprensión que solo copia las letras minúsculas de la lista original:
lowers_comp = [ letter for letter in word if letter.islower() ]
apacheconfDe nuevo, comprobamos que ambos métodos arrojan el mismo resultado mediante la sentencia assert:
assert lowers == lowers_comp
apacheconf