Python装饰器和类方法及求值——django memoize

标签 python class scope methods decorator

我有一个可用的 memoize 装饰器,它使用 Django 的缓存后端在一定时间内记住函数的结果。我专门将其应用于类方法。

我的装饰器看起来像:

def memoize(prefix='mysite', timeout=300, keygenfunc=None):
    # MUST SPECIFY A KEYGENFUNC(args, kwargs) WHICH MUST RETURN A STRING
    def funcwrap(meth):

      def keymaker(*args, **kwargs):
        key = prefix + '___' + meth.func_name + '___' + keygenfunc(args, kwargs)
        return key

      def invalidate(*args, **kwargs):
        key = keymaker(*args, **kwargs)
        cache.set(key, None, 1)

      def newfunc(*args, **kwargs):
        # construct key
        key = keymaker(*args, **kwargs)

        # is in cache?
        rv = cache.get(key)

        if rv is None:
          # cache miss
          rv = meth(*args, **kwargs)
          cache.set(key, rv, timeout)

        return rv

      newfunc.invalidate = invalidate
      return newfunc
    return funcwrap

我在类方法上使用它,所以像这样:

class StorageUnit(models.Model):
  @memoize(timeout=60*180, keygenfunc=lambda x,y: str(x[0].id))
  def someBigCalculation(self):
    ...
    return result

实际的内存过程完美无缺!也就是说,调用

myStorageUnitInstance.someBigCalculation()

正确使用缓存。好的,酷!

我的问题是当我尝试手动使我希望能够运行的特定实例的条目无效时

myStorageUnitInstance.someBigCalculation.invalidate()

但是,这是行不通的,因为“self”没有被传入,因此 key 也没有被生成。我收到一个“IndexError:元组索引超出范围”错误,指向我的 lambda 函数,如前所示。

当然可以成功调用:

myStorageUnitInstance.someBigCalculation.invalidate(myStorageUnitInstance)

这非常有效。但是当我已经引用了一个特定的实例时,它“感觉”是多余的。我怎样才能使 Python 将其视为实例绑定(bind)方法并因此正确填写“self”变量?

最佳答案

描述符必须始终在类上设置,而不是在实例上设置(有关所有详细信息,请参见 the how-to guide)。当然,在这种情况下,您甚至没有在实例上设置它,而是在另一个函数上设置它(并将其作为绑定(bind)方法的属性获取)。我认为使用你想要的语法的唯一方法是使 funcwrap 成为自定义类的实例(当然,哪个类必须是描述符类,即定义适当的 __get__ 方法,就像函数本质上做的那样) .然后 invalidate可以是该类的一个方法(或者,也许更好,另一个自定义类,其实例是由前面提到的描述符类的 __get__ 方法产生的“类似绑定(bind)方法的物质”),并最终到达 im_self您渴望的(这就是它在绑定(bind)方法中的命名方式)。

为您寻求的次要便利付出相当高的(概念和编码;-)代价 -- 足够高以至于我真的不想花一两个小时来完全开发它并测试它。但我希望我已经给了你足够明确的指示,如果你仍然热衷于此,你可以继续,而且如果有任何不清楚的地方或有什么东西阻碍你前进,我确实很乐意澄清并提供帮助。

关于Python装饰器和类方法及求值——django memoize,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1719527/

相关文章:

python - 如何在 Tkinter 中获取文本结束位置的行和列?

c++ - 在哪里定义具有模板和非模板成员的类?

ios - 从 firebase 检索子值到数组以在 TableView 单元格中使用

javascript - greasemonkey 沙箱和范围问题

python - 为什么我不能连续两次在 sys.stdin 中执行循环? (Python)

python - 了解每个用户的位置时间 : using the shift function

python - 空类的实例和对象的实例之间的区别?

class - 在 VBA 中使用自定义数据类型

javascript - 是否有默认方法来获取 jQueryUi 小部件中的内部属性?

Python 作业服务守护进程?