Generadores para Principiantes
Analogía: La Máquina de Chicles 🍬
Imagina una máquina de chicles:
No te da todos los chicles a la vez
Cada vez que giras la manivela te da un chicle
Puedes parar cuando quieras
La máquina recuerda dónde quedó para la próxima vez
Un generador es como esa máquina: te da valores uno por uno cuando los pides.
Los generadores son funciones especiales en Python que permiten producir una secuencia de valores de forma pausada y eficiente, en lugar de calcular todos los valores a la vez y guardarlos en memoria.
Diferencia clave: Función normal vs Generador
Función normal (usa return)
def numeros_cuadrados(n):
resultado = []
for i in range(n):
resultado.append(i ** 2)
return resultado
# Todos los valores se calculan y almacenan en memoria
lista = numeros_cuadrados(5)
print(lista) # [0, 1, 4, 9, 16]Generador (usa yield)
def numeros_cuadrados_gen(n):
for i in range(n):
yield i ** 2 # Produce un valor y se pausa
# Los valores se generan bajo demanda
generador = numeros_cuadrados_gen(5)
print(generador) # <generator object...>Cómo usar generadores
1. Iteración directa
def contador_hasta(n):
i = 0
while i < n:
yield i
i += 1
for numero in contador_hasta(3):
print(numero)
# Output: 0, 1, 22. Usando next()
def simple_generator():
yield "primero"
yield "segundo"
yield "tercero"
gen = simple_generator()
print(next(gen)) # "primero"
print(next(gen)) # "segundo"
print(next(gen)) # "tercero"
# print(next(gen)) # Error: StopIterationExpresiones de generador (más compactas)
Similar a las listas por comprensión, pero con paréntesis:
# Lista por comprensión (almacena todo en memoria)
lista = [x**2 for x in range(5)] # [0, 1, 4, 9, 16]
# Expresión de generador (genera bajo demanda)
generador = (x**2 for x in range(5))
print(list(generador)) # [0, 1, 4, 9, 16]Ejemplos prácticos para principiantes
Ejemplo 1: Generador infinito
def contador_infinito():
i = 0
while True:
yield i
i += 1
contador = contador_infinito()
print(next(contador)) # 0
print(next(contador)) # 1
print(next(contador)) # 2
# Y así continúa indefinidamente...Ejemplo 2: Procesar archivo grande
def leer_lineas_archivo(nombre_archivo):
with open(nombre_archivo, 'r') as archivo:
for linea in archivo:
yield linea.strip()
# Solo carga una línea a la vez en memoria
for linea in leer_lineas_archivo("datos.txt"):
print(linea)Ejemplo 3: Fibonacci con generador
def fibonacci(limite):
a, b = 0, 1
count = 0
while count < limite:
yield a
a, b = b, a + b
count += 1
# Genera solo los números que necesitas
for num in fibonacci(5):
print(num) # 0, 1, 1, 2, 3Ventajas de los generadores
Eficiencia en memoria: No almacenan todos los valores a la vez
Lazy evaluation: Los valores se calculan solo cuando se necesitan
Pueden representar secuencias infinitas
Mantenimiento de estado: Recuerdan dónde se quedaron
Cuándo usar generadores
✅ SÍ usar cuando:
Trabajas con grandes volúmenes de datos
No necesitas acceso aleatorio a los elementos
Quieres ahorrar memoria
Trabajas con flujos de datos o secuencias
❌ NO usar cuando:
Necesitas acceder a los elementos múltiples veces
Requieres acceso aleático a los elementos
Necesitas conocer la longitud de antemano
Resumen para principiantes
| Característica | Función normal | Generador |
|---|---|---|
| Retorno | return | yield |
| Memoria | Almacena todo | Genera bajo demanda |
| Estado | Se reinicia | Mantiene estado |
| Uso | Múltiples accesos | Flujo único |
Los generadores son una herramienta poderosa que te ayudará a escribir código más eficiente y elegante en Python. ¡Empieza con ejemplos simples y verás lo útiles que son!
¿Qué es un Generador?
Es una función que produce una secuencia de valores pero no los almacena todos en memoria. En lugar de usar return, usa yield.
Ejemplo 1: Generador Básico - Contador 🎯
def contador_generador(limite):
numero = 1
while numero <= limite:
yield numero # Pausa aquí y recuerda dónde quedó
numero += 1
# Usar el generador
mi_contador = contador_generador(5)
print("=== GIRANDO LA MÁQUINA ===")
print(next(mi_contador)) # Primer "giro" - Output: 1
print(next(mi_contador)) # Segundo "giro" - Output: 2
print(next(mi_contador)) # Tercer "giro" - Output: 3Output:
=== GIRANDO LA MÁQUINA ===
1
2
3Usando un bucle for (más común):
def contador_generador(limite):
numero = 1
while numero <= limite:
yield numero
numero += 1
print("=== CON BUCLE FOR ===")
for numero in contador_generador(5):
print(f"Chicle número: {numero}")Output:
=== CON BUCLE FOR ===
Chicle número: 1
Chicle número: 2
Chicle número: 3
Chicle número: 4
Chicle número: 5Ejemplo 2: Generador de Números Pares 🔢
def numeros_pares(limite):
numero = 0
while numero <= limite:
if numero % 2 == 0:
yield numero # Pausa y devuelve este número par
numero += 1
print("=== NÚMEROS PARES ===")
for par in numeros_pares(10):
print(f"Número par: {par}")Output:
=== NÚMEROS PARES ===
Número par: 0
Número par: 2
Número par: 4
Número par: 6
Número par: 8
Número par: 10Comparación con lista normal:
# CON LISTA (ocupa más memoria)
def pares_lista(limite):
resultado = []
for i in range(limite + 1):
if i % 2 == 0:
resultado.append(i)
return resultado
# CON GENERADOR (más eficiente en memoria)
def pares_generador(limite):
for i in range(limite + 1):
if i % 2 == 0:
yield i
print("Lista completa:", pares_lista(10)) # [0, 2, 4, 6, 8, 10]
print("Generador:")
for num in pares_generador(10):
print(num, end=" ") # 0 2 4 6 8 10Ejemplo 3: Generador de Mensajes Personalizados 🎁
def mensaje_generador(nombres):
for nombre in nombres:
mensaje = f"🎁 ¡Hola {nombre}! Tienes un regalo."
yield mensaje # Pausa y entrega un mensaje
# Lista de nombres
amigos = ["Ana", "Carlos", "María", "Pedro"]
print("=== ENTREGANDO MENSAJES ===")
mensajero = mensaje_generador(amigos)
# Entregamos los mensajes uno por uno
print(next(mensajero)) # 🎁 ¡Hola Ana! Tienes un regalo.
print(next(mensajero)) # 🎁 ¡Hola Carlos! Tienes un regalo.
print(next(mensajero)) # 🎁 ¡Hola María! Tienes un regalo.
# Podríamos seguir con next() o usar un bucleOutput:
=== ENTREGANDO MENSAJES ===
🎁 ¡Hola Ana! Tienes un regalo.
🎁 ¡Hola Carlos! Tienes un regalo.
🎁 ¡Hola María! Tienes un regalo.Ejemplo 4: Generador con Condición - Solo Números Grandes 🏗️
def numeros_grandes(numeros, minimo):
for numero in numeros:
if numero >= minimo:
yield f"🚀 Número grande: {numero}"
else:
yield f"🐜 Número pequeño: {numero}"
lista_numeros = [5, 15, 3, 25, 8, 30]
print("=== FILTRANDO NÚMEROS ===")
for mensaje in numeros_grandes(lista_numeros, 10):
print(mensaje)Output:
=== FILTRANDO NÚMEROS ===
🐜 Número pequeño: 5
🚀 Número grande: 15
🐜 Número pequeño: 3
🚀 Número grande: 25
🐜 Número pequeño: 8
🚀 Número grande: 30Ventajas de los Generadores
1. Ahorro de Memoria 💾
# MAL: Crea una lista gigante en memoria
def numeros_gigante_mal(limite):
return list(range(limite)) # ¡Ocupa mucha memoria!
# BIEN: Generador que produce números uno por uno
def numeros_gigante_bien(limite):
for i in range(limite):
yield i # Solo ocupa memoria para un número a la vez2. Pueden ser infinitos ♾️
def contador_infinito():
numero = 1
while True:
yield numero
numero += 1
# ¡Cuidado! Esto no crea un bucle infinito de inmediato
infinito = contador_infinito()
print(next(infinito)) # 1
print(next(infinito)) # 2
print(next(infinito)) # 3
# Podemos seguir para siempre...Resumen Visual
GENERADOR NORMAL: [1, 2, 3, 4, 5] → Te da TODOS los números de una vez
GENERADOR PYTHON: 1 → 2 → 3 → 4 → 5 → Te da UN número cada vez que pides
↑ ↑ ↑ ↑ ↑
yield yield yield yield yieldDiferencias Clave:
| Función Normal | Generador |
|---|---|
Usa return | Usa yield |
| Devuelve todo de una vez | Devuelve un valor a la vez |
| Olvida el estado | Recuerda dónde quedó |
| Ocupa más memoria | Muy eficiente en memoria |
Sintaxis Express: Generator Expressions
# Similar a list comprehension pero con paréntesis
lista = [x * 2 for x in range(5)] # [0, 2, 4, 6, 8]
generador = (x * 2 for x in range(5)) # Generator object
print("Lista:", lista)
print("Generador:", list(generador)) # Convertimos a lista para verPuntos Clave para Principiantes:
yieldpausa la función y recuerda el estadonext()continúa desde donde se pausóSon perezosos (lazy) - solo calculan cuando se necesita
Ideales para secuencias grandes o infinitas
Comentarios
Publicar un comentario