Hoo*_*pes 10 python decorator memoization descriptor
我正在尝试为类的实例方法构建一个装饰器来记忆结果.(之前已经完成了一百万次)但是,我希望能够在任何时候重置memoized缓存(例如,如果实例状态中的某些内容发生更改,这可能会更改无方法的结果)与它的args相关).所以,我试图建立一个装饰为一类,而不是一个函数,这样我可以有机会获得高速缓存作为一个类的成员.这导致我学习描述符的路径,特别是__get__
方法,这是我实际上被困的地方.我的代码看起来像这样:
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)
Run Code Online (Sandbox Code Playgroud)
这是清楚的和/或可能的吗?每次__get__
被调用时,我得到的memoized类,它失去了我的缓存,它的实际数据的一个全新的实例.我一直在努力__get__
,但没有取得多大进展.
是否有一个完全独立的方法解决这个问题,我完全不知道了?并且欢迎并赞赏所有建议/建议.谢谢.
我没有尝试计算实现的机制,而是memoized
从PythonDecoratorLibrary中获取了装饰器类,并修改了它以进行添加reset
.以下是结果; 我使用的技巧是为reset
装饰函数本身添加一个可调用属性.
class memoized2(object):
"""Decorator that caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned, and
not re-evaluated.
"""
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
try:
return self.cache[args]
except KeyError:
value = self.func(*args)
self.cache[args] = value
return value
except TypeError:
# uncachable -- for instance, passing a list as an argument.
# Better to not cache than to blow up entirely.
return self.func(*args)
def __repr__(self):
"""Return the function's docstring."""
return self.func.__doc__
def __get__(self, obj, objtype):
"""Support instance methods."""
fn = functools.partial(self.__call__, obj)
fn.reset = self._reset
return fn
def _reset(self):
self.cache = {}
class my_class:
@memoized2
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)
Run Code Online (Sandbox Code Playgroud)