Próbuję zbudować dekorator dla metody instancji klasy, która zapamiętuje wynik. (Dokonano tego już milion razy wcześniej). Chciałbym jednak móc zresetować pamięć podręczną w dowolnym miejscu (powiedzmy, jeśli zmieni się stan w stanie instancji, co może zmienić wynik metody, która nie ma nic wspólnego). zrobić z jego argumentami). Tak więc, próbowałem zbudować dekorator jako klasę zamiast funkcji, tak żebym mógł mieć dostęp do pamięci podręcznej jako członek klasy. Doprowadziło mnie to do poznania deskryptorów, a konkretnie metody __get__
, w której faktycznie utknąłem. Mój kod wygląda następująco:python resettable metoda instancji memoization decorator
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)
Czy to jest jasne i/lub możliwe? Za każdym razem, gdy wywoływana jest nazwa __get__
, otrzymuję zupełnie nową instancję klasy pamiętanej, która traci pamięć podręczną z rzeczywistymi danymi w niej. Ciężko pracowałem z __get__
, ale nie robię dużego postępu.
Czy istnieje całkowicie oddzielne podejście do tego problemu, którego zupełnie mi brakuje? I wszystkie rady/sugestie są mile widziane i doceniane. Dzięki.
nie głębiej w kodzie, ale dla lepszej wydajności należy użyć 'jeśli cache .has_key (...): return cache [...] 'zamiast przechwytywania' KeyError'. – khachik
@khachik: 'klucz w pamięci podręcznej' jest lepszy, ponieważ' has_key' jest przestarzałe. – delnan
Należy pamiętać, że celem funkcji przywołania jest to, że wywołanie funkcji z tymi samymi argumentami daje takie same wyniki. Jeśli naprawdę potrzebujesz zresetować pamięć podręczną na podstawie stanu instancji, może powinieneś rozważyć utrzymanie pamięci podręcznej w instancji zamiast pamiętanego dekoratora. – Falmarri