Hamburger Icon
Guía de iterables con Python

Guía de iterables con Python

¿Qué son los iterables en Python? ¿Para qué sirven? ¿Qué casos de uso habituales tienen? ¿Cómo podemos crear nuestros propios iterables? ¿Qué diferencia hay entre usar yield y return en una función que devuelve un iterable? Vamos a responder a todas estas dudas.

Qué son los iterables

Un iterable es un objeto que puede ser recorrido por un bucle for, es decir, que puede devolver uno a uno sus elementos. Por ejemplo, las listas, las tuplas, los diccionarios, las cadenas de texto y los ficheros son iterables, ya que podemos hacer algo como esto:

nums = [1,2,3,4]
for num in nums:
    print(num)

La salida sería:

1
2
3
4

Crear tus propios iterables

Para que un objeto sea iterable, debe implementar el método mágico __iter__(), que debe devolver un iterador. Un iterador es un objeto que implementa el método __next__(), que debe devolver el siguiente elemento del iterable o lanzar una excepción StopIteration si no hay más elementos.

Por ejemplo, podemos crear una clase que represente una secuencia de números pares y que sea un iterable:

class EvenNumbers:
    def __init__(self, limit):
        self.limit = limit
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.counter < self.limit:
            next_even = self.counter * 2
            self.counter += 1
            return next_even
        else:
            raise StopIteration

Ahora podemos crear un objeto de esta clase y recorrerlo con un for:

even_numbers = EvenNumbers(10)
for num in even_numbers:
    print(num)

La salida sería:

0
2
4
6
8
10
12
14
16
18

Como vemos, el método __iter__() devuelve el propio objeto (self), que actúa como iterador, y el método __next__() devuelve el siguiente número par hasta llegar al límite establecido. Si intentamos obtener más elementos, se lanza la excepción StopIteration, que indica al bucle for que debe terminar.

Conociendo y dominando estos métodos especiales podemos crear nuestros propios iterables, algo que puede resultar muy útil en el procesamiento de datos.

Crear tus iterables modo Dios

Una forma más sencilla de crear un iterable es usando una función generadora, es decir, una función que usa la palabra clave yield en vez de return para devolver los elementos.

La instrucción yield no termina la ejecución de la función, sino que la pausa hasta la siguiente llamada. Por ejemplo, podemos reescribir la clase EvenNumbers como una función generadora:

def even_numbers(limit):
    counter = 0
    while counter < limit:
        yield counter * 2
        counter += 1

Ahora podemos usar la función pares como un iterable:

for num in even_numbers(10):
    print(num)

La salida sería la misma que antes. La ventaja de usar yield es que simplifica el código y evita tener que manejar la excepción StopIteration. Es lo que llamaríamos azúcar sintáctico.

Una vez entiendes el concepto mediante el uso de una clase y las funciones de los iterables, pasar a usar yield es una muy buena solución.

Eso sí, no te aconsejo pasar al azúcar antes de entender qué estás haciendo con tu código, que luego pasa lo que pasa.

Casos de uso y conclusión

Los iterables son muy útiles en Python, ya que nos permiten trabajar con colecciones de datos de forma eficiente y elegante. Algunos casos de uso habituales son:

  • Leer ficheros línea por línea sin cargarlos enteros en memoria
  • Generar secuencias infinitas o muy largas sin almacenarlas en memoria
  • Aplicar operaciones lazy (algo así como operaciones "perezosas") sobre los datos, es decir, solo cuando se necesitan
  • Usar comprensiones de listas, diccionarios o conjuntos para crear colecciones a partir de iterables
  • Usar funciones de alto nivel como map, filter, zip o reduce para procesar iterables

En conclusión, los iterables son una característica fundamental de Python que nos facilita el manejo de datos y el diseño de algoritmos. Espero que esta guía te haya sido útil para entender qué son los iterables, cómo se crean y cómo se usan en Python.