Tutorial: Domina los Generadores en Python con la «Fábrica de Donas»

Cuando trabajamos con archivos gigantes (como el de 2 GB que mencionamos antes), no podemos meter todo al mismo tiempo en la memoria RAM. Necesitamos un sistema que nos entregue las cosas bajo demanda. En Python, eso se hace con Generadores y la palabra clave yield.

Para entenderlo, imagínate que vas a una pastelería, pero el repostero no tiene las donas listas en vitrina; las hace justo en el momento en que se las pides.

El Código Base

Aquí tienes el código de nuestra pastelería de alta eficiencia:

Python

# 1. Primero definimos la función (la receta de la fábrica)
def fabrica_de_donas():
    print("-> Repostero entra a la cocina...")
    yield "🍩 Dona de Chocolate"
    
    print("-> Repostero retoma el trabajo...")
    yield "🍩 Dona de Glaseada"
    
    print("-> Repostero hace el último esfuerzo...")
    yield "🍩 Dona de Rellena de Manjar"

# 2. Activamos la fábrica (Creamos el generador)
mis_donas = fabrica_de_donas()

# 3. Pedimos las donas una por una
print(next(mis_donas))
print("--- El cliente se tomó un café y pide otra ---")
print(next(mis_donas))

Paso a Paso: ¿Qué está pasando realmente?

Vamos a desmenuzar el código para entender la magia de la RAM y el flujo de ejecución.

Paso 1: La Receta (def fabrica_de_donas())

En las funciones normales usas return para entregar un resultado y terminar la función. Aquí usamos yield.

💡 La regla de oro de yield: Entrega lo que le pidas, pero congela la función en esa línea exacta. Guarda el estado de la cocina (las variables, el orden) y se queda esperando.

Paso 2: Encender la Máquina (mis_donas = fabrica_de_donas())

Al ejecutar esta línea, sorpresa: ¡no se imprime nada en la consola! El repostero ni siquiera ha entrado a la cocina. Al guardar la función en mis_donas, Python no ejecuta el código, solo crea un objeto generador (el contrato de que la fábrica está lista para trabajar).

Paso 3: El primer next(mis_donas)

Aquí es donde el cliente llega a la barra y dice: «Quiero mi primera dona».

  1. El código de la función arranca.
  2. Se imprime: -> Repostero entra a la cocina...
  3. Llega al primer yield "🍩 Dona de Chocolate".
  4. El programa te entrega la dona en la consola y la función se congela ahí mismo.

El intermedio: El café (print("--- El cliente..."))

Mientras el cliente se toma su café, la memoria RAM está en paz. No hay donas guardadas flotando en el sistema ocupando espacio. La segunda y tercera dona aún no existen.

Paso 4: El segundo next(mis_donas)

El cliente pide otra dona. Python va a la función y, en lugar de empezar desde el principio, recuerda dónde se había quedado congelado.

  1. Se descongela justo después del primer yield.
  2. Se imprime: -> Repostero retoma el trabajo...
  3. Llega al segundo yield "🍩 Dona de Glaseada", te la entrega y se vuelve a congelar.

¿Qué pasa si ejecutas este código?

La salida en tu consola se verá exactamente así:

Plaintext

-> Repostero entra a la cocina...
🍩 Dona de Chocolate
--- El cliente se tomó un café y pide otra ---
-> Repostero retoma el trabajo...
🍩 Dona de Glaseada

⚠️ Nota Importante: Como solo llamamos a next() dos veces, el tercer yield (la dona de Manjar) nunca se ejecutó. El repostero jamás hizo ese «último esfuerzo». Esto demuestra cómo ahorramos procesador y memoria: si no lo pides, Python no gasta recursos en crearlo.

¿Y si quiero todas las donas automáticas? (El truco del foreach)

Si en vez de usar next() manualmente quieres que el proceso sea automático (como cuando procesamos las líneas del archivo de 2GB), puedes usar un ciclo for. El ciclo for se encarga de llamar a next() por ti en cada vuelta hasta que la fábrica se quede sin yields.

Python

# Si hacemos esto, el repostero cocinará todo el menú de corrido, 
# pero siempre una por una en la RAM:
for dona in fabrica_de_donas():
    print(f"Cliente recibe: {dona}")

Conclusión

  • Funciones con return: Hacen todas las donas de golpe, las meten en una caja gigante (RAM) y te entregan la caja. (Si la caja es de 2 GB, tu servidor puede explotar).
  • Funciones con yield: Te entregan una dona fresca en la mano. Cuando te la terminas, te dan la siguiente. Tu «caja» de RAM solo necesita espacio para una dona a la vez.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *