Tengo una función llamada runquery
que hace llamadas a una base de datos y luego cede las filas, una por una. Escribí un decorador de memoise (o más exactamente, acabo de robar uno de this stackoverflow question), pero en las llamadas siguientes simplemente produce una secuencia vacía, presumiblemente porque los valores de un generador solo pueden obtenerse una vez.¿Puedo memorizar un generador de Python?
¿Cómo podría modificar el decorador de memoria que funciona para los generadores Python? Me doy cuenta de que tendré que almacenarlo en la memoria en algún momento, pero me gustaría manejar esto dentro del decorador y no modificar la función original.
El código actual de la función memoization es:
def memoized(f):
# Warning: Doesn't work if f yields values
cache={}
def ret(*args):
if args in cache:
return cache[args]
else:
answer=f(*args)
cache[args]=answer
return answer
return ret
¡Gracias por su ilustración! Llevé años para entender la forma de usar 'tee'. __Pero__ creo que hay un problema al verificar la instancia: debes probar contra 'collections.Iterable', como prueba contra' types.GeneratorType' solo funciona una vez: al devolver el iterador en caché (objeto 'iterator.tee') al tercero llamar a la función, la caché devolverá un iterador agotado. –
¡Tienes razón! Sin embargo, las pruebas en contra de 'collections.Iterable' también serían erróneas, ya que las listas, las cadenas, etc. son también iterables. Cambié los conjuntos a '(GeneratorType, _tee)', por lo que también funciona para los objetos de tee. – Robin
Sí, definitivamente es un poco exagerado, pero, en Python 2.7, no hay ningún objeto '_tee' en' itertools', y la función 'itertools.tee' devuelve objetos' itertools.tee'. Obviamente, esta no es su clase, por lo que probar contra 'itertools.tee' no tiene sentido (y tampoco funciona), de ahí mi propuesta con' collections.Iterable'. ¿Bajo qué versión de Python has probado tu código? –