如何正确地使用`functools.lru_cache`装饰一个`classmethod`?

12

我尝试使用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

1
classmethod 必须放在最后使用,这意味着它必须位于您的装饰器链的顶部。 - SyntaxVoid
2个回答

28

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

因此,您希望由lru_cache装饰的函数被转换为类方法。

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

4

已选择的答案完全正确,但在此添加另一个帖子。如果您想将缓存存储绑定到每个类,而不是将单个存储共享给所有其子类,那么还有另一种选择: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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接