Estoy intentando construir un decorador para un método de instancia de una clase que memorizará el resultado. (Esto se ha hecho un millón de veces antes) Sin embargo, me gustaría la opción de poder restablecer el caché memorable en cualquier punto (por ejemplo, si algo en el estado de la instancia cambia, lo que podría cambiar el resultado del método sin tener nada para hacer con sus argumentos). Entonces, intenté construir un decorador como una clase en lugar de una función, para poder tener acceso a la memoria caché como miembro de la clase. Esto me llevó por el camino de aprender sobre los descriptores, específicamente el método __get__
, que es donde estoy realmente atrapado. Mi código es el siguiente manera:instancia de python que restablece el método de memoial decorador
import time
class memoized(object):
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args, **kwargs):
key = (self.func, args, frozenset(kwargs.iteritems()))
try:
return self.cache[key]
except KeyError:
self.cache[key] = self.func(*args, **kwargs)
return self.cache[key]
except TypeError:
# uncacheable, so just return calculated value without caching
return self.func(*args, **kwargs)
# self == instance of memoized
# obj == instance of my_class
# objtype == class object of __main__.my_class
def __get__(self, obj, objtype=None):
"""Support instance methods"""
if obj is None:
return self
# new_func is the bound method my_func of my_class instance
new_func = self.func.__get__(obj, objtype)
# instantiates a brand new class...this is not helping us, because it's a
# new class each time, which starts with a fresh cache
return self.__class__(new_func)
# new method that will allow me to reset the memoized cache
def reset(self):
print "IN RESET"
self.cache = {}
class my_class:
@memoized
def my_func(self, val):
print "in my_func"
time.sleep(2)
return val
c = my_class()
print "should take time"
print c.my_func(55)
print
print "should be instant"
print c.my_func(55)
print
c.my_func.reset()
print "should take time"
print c.my_func(55)
¿Está claro y/o posible? Cada vez que se llama al __get__
, obtengo una nueva instancia de la clase memoial, que me pierde el caché con los datos reales. He estado trabajando duro con __get__
, pero no estoy progresando mucho.
¿Hay un enfoque completamente separado de este problema que me falta por completo? Y todos los consejos/sugerencias son bienvenidos y apreciados. Gracias.
no fui más profundo en su código, pero para un mejor rendimiento que debe utilizar 'si caché .has_key (...): devuelve el caché [...] 'en lugar de capturar' KeyError'. – khachik
@khachik: 'key in cache' es mejor, ya que' has_key' está en desuso. – delnan
Tenga en cuenta que el punto de memorización es que una llamada a función con los mismos argumentos produce el mismo resultado. Si realmente necesita restablecer el caché en función del estado de la instancia, tal vez debería considerar conservar el caché en la instancia en lugar de un decorador con memoria. – Falmarri