这个问题是python resettable instance method memoization decorator答案的后续问题。 事实上,我会将此作为对该答案的评论,但我没有(但我希望)有足够的声誉。
在那个答案中,@ aix提供了一种使用装饰器重置记忆函数的好方法。
该答案的“问题”是,为某个装饰方法调用reset
会重置所有实例的缓存。使用@aix定义的相同类的示例应该清楚说明:
c = my_class()
print c.my_func(55)
# This time the function is computed and stored in cache
print c.my_func(55)
# This second call is cached... no computation needed
d = my_class()
d.my_func.reset()
print c.my_func(55)
# This third call is also computed, since the cache has been cleared
我认为d.my_func.reset()
应该只清除d.my_func
的预先计算值的缓存,而不是my_class
的所有其他实例。
我有一个半解决方案,不能完全说服,但我想有人可以改进。
我修改了reset()
方法并引入了参数instance
:
def _reset(self,instance):
for cached in self.cache.keys():
if cached[0] == instance:
del self.cache[cached]
现在,如果我这样做:
c = my_class()
print c.my_func(55)
# This time the function is computed and stored in cache
print c.my_func(55)
# This second call is cached
d = my_class()
d.my_func.reset(d)
print c.my_func(55)
# Now this third call is cached
然而,调用重置方法的方式:d.my_func.reset(d)
似乎(至少)难看,但我找不到更好的解决方案......有没有人有想法?
谢谢!
修改
对于记录:不是将实例作为参数传递,而是可以在修改装饰器的__get__
方法时获得相同的行为。
在self.original_self = obj
方法中添加__get__(self, obj, objtype)
,并在if cached[0] == instance
方法中将if cached[0] == self.original_self
替换为_reset
。这解决了这个问题!
答案 0 :(得分:0)
您可以使用方法的__self__
属性(在本例中为self.__self__
)来查找它所绑定的类实例(而不是必须传递实例) )。
答案 1 :(得分:0)
2种可能性-也存储在实例__dict__
内,而不是全局备忘单:
def MemoMeth(meth):
"""Memoizer for class methods (uses instance __dict__)
Example:
class C:
@MemoMeth
def slowmeth(self, a, b): ...
"""
class _MemoMeth:
def __init__(self, this):
self.this = this
def __call__(self, *args):
memo = self.this.__dict__.setdefault(_MemoMeth, {})
try:
return memo[args][1]
except:
memo[args] = tr = time.time(), meth(self.this, *args)
return tr[1]
def reset(self):
self.this.__dict__.setdefault(_MemoMeth, {}).clear()
return property(_MemoMeth)
此操作每次访问使用线程本地存储而不是新的包装对象:
def MemoMeth3(meth):
"""Memoizer for class methods (uses instance __dict__)
Example:
class C:
@MemoMeth3
def slowmeth(self, a, b): ...
"""
tls = threading.local()
class MemoProperty(object):
def __call__(self, *args):
memo = tls.instance.__dict__.setdefault(self, {})
try:
return memo[args][1]
except:
memo[args] = tr = time.time(), meth(tls.instance, *args)
return tr[1]
def reset(self):
tls.instance.__dict__.setdefault(self, {}).clear()
def __get__(self, instance, owner):
tls.instance = instance
return self
return MemoProperty()