【问题标题】:How do I properly decorate a `classmethod` with `functools.lru_cache`?如何用 `functools.lru_cache` 正确装饰`classmethod`?
【发布时间】:2020-02-27 04:16:15
【问题描述】:

我尝试用functools.lru_cache 装饰classmethod。我的尝试失败了:

import functools
class K:
    @functools.lru_cache(maxsize=32)
    @classmethod
    def mthd(i, stryng: str): \
        return stryng

obj = K()

错误信息来自functools.lru_cache:

TypeError: the first argument must be callable

【问题讨论】:

  • classmethod 必须最后使用.. 这意味着它必须位于装饰器链的顶部

标签: python python-3.x decorator static-methods python-decorators


【解决方案1】:

类方法本身是不可调用的。 (可调用的是类方法的__get__方法返回的对象。)

因此,您希望将lru_cache 修饰的函数转换为类方法。

@classmethod
@functools.lru_cache(maxsize=32)
def mthd(cls, stryng: str):
    return stryng

【讨论】:

    【解决方案2】:

    所选答案完全正确,但要添加另一个帖子。如果您想将缓存存储绑定到每个类,而不是将单个存储共享给它的所有子类,还有另一个选项methodtools

    import functools
    import methodtools
    
    
    class K:
        @classmethod
        @functools.lru_cache(maxsize=1)
        def mthd(cls, s: str):
            print('functools', s)
            return s
    
        @methodtools.lru_cache(maxsize=1)  # note that methodtools wraps classmethod
        @classmethod
        def mthd2(cls, s: str):
            print('methodtools', s)
            return s
    
    
    class L(K):
        pass
    
    
    K.mthd('1')
    L.mthd('2')
    K.mthd2('1')
    L.mthd2('2')
    
    K.mthd('1')  # functools share the storage
    L.mthd('2')
    K.mthd2('1')  # methodtools doesn't share the storage
    L.mthd2('2')
    
    

    那么结果就是

    $ python example.py
    functools 1
    functools 2
    methodtools 1
    methodtools 2
    functools 1
    functools 2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-08
      • 2016-03-17
      • 2021-03-30
      • 2021-01-17
      • 2011-12-15
      • 1970-01-01
      • 2020-10-10
      相关资源
      最近更新 更多