Python: Crear generadores repetibles (repeating generators)
Posted on Tue 09 February 2016 in Python
Los generadores en Python son "one-shot" - solo se pueden iterar una vez. ¿Cómo crear generadores que se puedan reutilizar múltiples veces?
El problema¶
def mi_generador():
yield 1
yield 2
yield 3
gen = mi_generador()
print(list(gen)) # [1, 2, 3]
print(list(gen)) # [] - ¡Vacío!
Solución 1: Enfoque con clase (Más robusto)¶
def multigen(gen_func):
class _multigen(object):
def __init__(self, *args, **kwargs):
self.__args = args
self.__kwargs = kwargs
def __iter__(self):
return gen_func(*self.__args, **self.__kwargs)
return _multigen
# Uso
@multigen
def mi_generador_repetible(max_num):
for i in range(max_num):
yield i
gen = mi_generador_repetible(3)
print(list(gen)) # [0, 1, 2]
print(list(gen)) # [0, 1, 2] - ¡Funciona!
Solución 2: itertools.cycle() para secuencias infinitas¶
import itertools
# Repetir infinitamente una secuencia
repeating_gen = itertools.cycle([1, 2, 3])
# Tomar solo los primeros 9 elementos
resultado = list(itertools.islice(repeating_gen, 9))
print(resultado) # [1, 2, 3, 1, 2, 3, 1, 2, 3]
Solución 3: Lambda wrapper (Simple)¶
def mi_generador():
yield 1
yield 2
yield 3
# Wrapper para crear nueva instancia cada vez
generador_repetible = lambda: mi_generador()
print(list(generador_repetible())) # [1, 2, 3]
print(list(generador_repetible())) # [1, 2, 3]
Solución 4: Función factory¶
def crear_generador(datos):
def generador():
for item in datos:
yield item
return generador
# Uso
gen_factory = crear_generador([1, 2, 3])
gen1 = gen_factory()
gen2 = gen_factory()
print(list(gen1)) # [1, 2, 3]
print(list(gen2)) # [1, 2, 3]
¿Cuándo usar cada enfoque?¶
Clase decorador (@multigen)¶
- Generadores complejos con parámetros
- Máxima flexibilidad y reutilización
- Preserva metadatos del generador original
itertools.cycle()¶
- Repetición infinita de secuencias pequeñas
- Patrones cíclicos conocidos
- Muy eficiente en memoria
Lambda wrapper¶
- Casos simples sin parámetros
- Prototipado rápido
- Generadores sin estado
Factory function¶
- Balance entre simplicidad y flexibilidad
- Generadores con configuración inicial
- Código más explícito
Consideraciones de rendimiento¶
⚠️ Memoria: Los generadores repetibles pueden requerir almacenar parámetros iniciales
⚠️ CPU: Cada iteración recalcula desde el inicio
La elección depende de si necesitas repetición exacta o reutilización eficiente.
Fuente original: Stack Overflow