generadores-en-python

Qué es y cómo usar generadores en Python

En Python, los generadores son una herramienta permiten generar secuencias de datos, centrados con la eficiencia como objetivo.

Para ello, a diferencia de las listas, los generadores no almacenan todos los elementos en la memoria, sino que los producen sobre la marcha.

Esto los hace hace muy útiles para trabajar con grandes conjuntos de datos o flujos de datos continuos, ya que los elementos se generan solo cuando se necesitan (y solo si se necesitan).

Su principal ventaja es que son mucho más eficientes en el uso de la memoria que las listas (porque no almacenan todos los elementos en la memoria a la vez)

Qué son los generadores

Un generador es una función que emplea la palabra reservada yield en lugar de return (yield podría interpretarse como “cede el paso”).

La palabra clave yield permite que una función produzca un valor, pero a la vez “recuerde” su estado. Esto permite que la ejecución pueda se reanude en ese punto en la siguiente llamada.

Vamos a verlo con un ejemplo,

def generador_simple():
    yield 1
    yield 2
    yield 3

Cuando se llama a generador_simple(), no se ejecuta inmediatamente el código dentro de la función. En su lugar, devuelve un objeto generador que puede ser iterado para producir los valores.

Las objeto generador creado no es invocable por si mismo. En su lugar, “se les solicita” el siguiente valor con next(). Por ejemplo así,

gen = generador_simple()
print(next(gen))  # Salida: 1
print(next(gen))  # Salida: 2
print(next(gen))  # Salida: 3

En este ejemplo

  • Usamos la función generador generador_simple() para crear un objeto generador gen
  • Se usa next(gen) para obtener el siguiente valor producido por el generador
  • Cuando no quedan más valores por producir, el generador lanza una excepción StopIteration

Generadores con Bucles

La mayoría de los generadores se crean utilizando bucles para producir una secuencia de valores.

def contar_hasta(n):
    contador = 1
    while contador <= n:
        yield contador
        contador += 1

Esta función generadora

  • Comienza devolviendo contador con valor a 1
  • Cada vez que se llama a la función, esta “despierta” en el bucle while. Incrementa el valor, hace el loop, y devuelve el nuevo contador
  • Cuando contador vale 5, el bucle acaba, y la secuencia termina.

También es muy frecuente que el uso de los generadores se haga desde un bucle. Por ejemplo, es muy habitual usarlos junto a for.

for numero in contar_hasta(5):
    print(numero)

# salida: 1 2 3 4 5

Generadores combinados

Los generadores pueden ser anidados para manejar secuencias más complejas.

def generador_anidado():
    yield from range(3)
    yield from range(10, 13)

for numero in generador_anidado():
    print(numero)

# salida: 0 1 2 10 11 12

En este ejemplo, yield from delega la producción de valores a otro generador o iterable.

  • En primer lugar, la función devuelve los valores generados por range(3)
  • Cuando termina, suministra los valores desde range(10, 13)
  • Cuando ambos terminan, se termina la secuencia

Generadores con expresiones

Python también permite crear generadores usando una sintaxis similar a las comprensiones de listas, conocida como “comprensión de generadores”.

gen = (x**2 for x in range(10))

for numero in gen:
    print(numero)

# salida: 0 1 4 9 16 25 36 49 64 81