繁体   English   中英

python resettable memoization 装饰器(对于某个实例)

[英]python resettable memoization decorator (for a certain instance)

这个问题是对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

但是,调用 reset 方法的方式: d.my_func.reset(d)看起来(至少)丑陋,但我一直没能找到更好的解决方案......有没有人有一些想法?

谢谢!

编辑

作为记录:您可以通过修改装饰器的__get__方法获得相同的行为,而不是将实例作为参数传递。

添加self.original_self = obj__get__(self, obj, objtype)方法和替代if cached[0] == instanceif cached[0] == self.original_self_reset方法。 这解决了问题!

2 种可能性 - 也存储在实例__dict__而不是全局备忘录 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()

您可以使用该方法的__self__属性(在本例中为self.__self__ )来查找它绑定到的类实例(而不必同时传递该实例)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM