Generadores en Python: Iteración Eficiente y Casos de Uso Avanzados
Generadores en Python
Descubre cómo los generadores de Python simplifican la iteración, reducen código boilerplate y mejoran el uso de memoria comparado con iteradores tradicionales.
¿Qué Son los Generadores?
Construir un iterador personalizado en Python usualmente requiere una clase que implemente __iter__() y __next__(), gestione estado interno y lance StopIteration al terminar. Los generadores eliminan este boilerplate permitiéndote escribir una función simple que produce valores uno a la vez.
En resumen, un generador es una función que devuelve un iterador. El cuerpo de la función se ejecuta perezosamente, pausando después de cada yield y reanudando en llamadas subsiguientes.
Crear Generadores en Python
Definir un generador es tan simple como escribir una función normal y reemplazar return con yield:
def mi_gen():
n = 1
print('Esto se imprime primero')
yield n
n += 1
print('Esto se imprime segundo')
yield n
n += 1
print('Esto se imprime al final')
yield n
Llamar a mi_gen() devuelve un iterador que empieza a ejecutar solo cuando se llama next().
a = mi_gen()
next(a) # imprime primer mensaje y devuelve 1
next(a) # imprime segundo mensaje y devuelve 2
next(a) # imprime último mensaje y devuelve 3
next(a) # lanza StopIteration
Las variables locales persisten entre yields, pero el generador solo puede iterarse una vez. Para reiniciar, crea una nueva instancia.
Como un generador es un iterador, puedes iterar sobre él directamente:
for item in mi_gen():
print(item)
Patrones Comunes de Generadores
Invertir una Cadena
def invertir_str(s):
for i in range(len(s)-1, -1, -1):
yield s[i]
for char in invertir_str('hola'):
print(char)
Funciona con cualquier iterable (lista, tupla, etc.).
Expresiones Generadoras
Generadores anónimos pueden crearse con paréntesis, similar a list comprehensions:
mi_lista = [1, 3, 6, 10]
# List comprehension
cuadrados_lista = [x**2 for x in mi_lista]
# Expresión generadora
cuadrados_gen = (x**2 for x in mi_lista)
print(cuadrados_lista)
print(cuadrados_gen)
El generador produce valores bajo demanda:
a = (x**2 for x in mi_lista)
print(next(a)) # 1
print(next(a)) # 9
print(next(a)) # 36
print(next(a)) # 100
next(a) # StopIteration
Las expresiones generadoras pueden pasarse directamente a funciones como sum o max sin paréntesis circundantes.
¿Por Qué Usar Generadores?
- Implementación Concisa: Reemplaza clases de iterador verbosas con unas pocas líneas de código.
- Eficiencia de Memoria: Produce un elemento a la vez, ideal para secuencias grandes o infinitas.
- Streams Infinitos: Representa fuentes de datos interminables (ej.
while True: yield). - Composición de Pipelines: Encadena múltiples generadores para procesamiento de datos limpio y legible.
Ejemplo: Potencia de Dos
def pot_dos_gen(max_n=0):
n = 0
while n < max_n:
yield 2 ** n
n += 1
Ejemplo: Sumando Cuadrados de Números Fibonacci
def numeros_fibonacci(count):
a, b = 0, 1
for _ in range(count):
a, b = b, a + b
yield a
def cuadrado(nums):
for n in nums:
yield n ** 2
print(sum(cuadrado(numeros_fibonacci(10)))) # 4895
Los generadores permiten código elegante, eficiente y mantenible para una amplia gama de escenarios de iteración.
python
- Dominando operadores en Python: Guía completa
- Dominando argumentos de funciones en Python: Posicionales, por palabra clave y por defecto
- Dominando Diccionarios en Python: Creación, Manipulación y Técnicas Avanzadas
- Generadores en Python: Iteración Eficiente y Casos de Uso Avanzados
- Explicación de Closures en Python: Cómo las Funciones Anidadas Capturan Variables
- Dominando Decoradores en Python: Mejora Funciones con Técnicas Expertas
- Dominando las funciones lambda en Python: ejemplos prácticos y mejores prácticas
- Función abs() en Python: calcular valores absolutos para números y complejos
- Función round() en Python explicada con ejemplos prácticos
- Dominando la función map() de Python: sintaxis, ejemplos y mejores prácticas
- Dominando yield en Python: Generadores vs Return – Guía práctica