Je tente de construire un décorateur pour une méthode d'instance d'une classe qui mémoize le résultat. (Cela a été fait un million de fois auparavant) Cependant, je voudrais pouvoir réinitialiser le cache memoized à tout moment (par exemple, si quelque chose change dans l'état de l'instance, ce qui pourrait changer le résultat de la méthode n'ayant rien à faire avec ses args). J'ai donc essayé de construire un décorateur en tant que classe au lieu d'une fonction, de sorte que je puisse avoir accès au cache en tant que membre de la classe. Cela m'a conduit sur le chemin de l'apprentissage des descripteurs, en particulier la méthode __get__
, qui est où je suis réellement coincé. Mon code ressemble à ceci:python réinitialisable instance méthode memoization décorateur
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-ce clair et/ou possible? Chaque fois que __get__
est appelée, j'obtiens une nouvelle instance de la classe memoized, qui me perd le cache avec des données réelles. J'ai travaillé dur avec __get__
, mais ne fais pas beaucoup de progrès.
Existe-t-il une approche complètement séparée de ce problème qui me manque complètement? Et tous les conseils/suggestions sont les bienvenus et appréciés. Merci.
Je ne suis pas plus loin dans votre code, mais pour de meilleures performances, vous devriez utiliser 'si le cache .has_key (...): retourne le cache [...] 'au lieu d'attraper' KeyError'. – khachik
@khachik: "key in cache" est meilleur, car 'has_key' est obsolète. – delnan
Gardez à l'esprit que le point de mémoization est qu'un appel de fonction avec les mêmes arguments produit la même sortie. Si vous avez vraiment besoin de réinitialiser le cache en fonction de l'état de l'instance, vous devriez peut-être envisager de conserver le cache dans l'instance au lieu d'un décorateur mémo. – Falmarri