Python 为什么functools.lru\u cache在使用普通方法时不调用cache\uu\u

Python 为什么functools.lru\u cache在使用普通方法时不调用cache\uu\u,python,caching,magic-methods,Python,Caching,Magic Methods,我一直在尝试使functools.lru\u缓存特定于中所述的实例,但在\uuuu调用方法上使用它们的解决方案时失败 class test: def __init__(self): self.method = lru_cache()(self.method) self.__call__ = lru_cache()(self.__call__) def method(self, x): print('method', end=' '

我一直在尝试使
functools.lru\u缓存
特定于中所述的实例,但在
\uuuu调用
方法上使用它们的解决方案时失败

class test:
    def __init__(self):
        self.method = lru_cache()(self.method)
        self.__call__ = lru_cache()(self.__call__)

    def method(self, x):
        print('method', end=' ')
        return x

    def __call__(self, x):
        print('__call__', end=' ')
        return x

b = test()
# b.method is cached as expected
print(b.method(1)) # method 1
print(b.method(1)) # 1

# __call__ is executed every time
print(b(1)) # __call__ 1
print(b(1)) # __call__ 1
因此,当使用此方法包装时,
\uuuuuu调用
的结果不会被缓存。
\uuuuu call\uuuuu
上的缓存甚至不注册已调用的函数,不可破坏的值不会抛出错误

print(b.method.cache_info())
# CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
print(b.__call__.cache_info())
# CacheInfo(hits=0, misses=0, maxsize=128, currsize=0)

print(b.call({})) # __call__ {}
print(b.method({})) # ... TypeError: unhashable type: 'dict'

这是由于类属性和实例属性之间的差异造成的。当访问属性(例如
方法
)时,python首先检查实例属性。如果您没有分配给
self.method
,它将找不到。然后检查类属性,这相当于
self.\uu class\uuu.method
。分配给仅更新实例属性的
self.method
,不会更改此函数的值


然而,
b(1)
变成了
b.\uu类
。\uu调用(b,1),它使用了
\uu调用
b的原始类定义。由于
方法使用了实例定义,因此它将以与
方法
相同的方式缓存。

原始答案非常好

我附上这个问题的另一个解决办法。
methodtools.lru\u缓存将按预期工作

从methodtools导入lru\U缓存
课堂测试:
@lru_缓存
定义调用(self,x):
打印(“调用”,结束=”)
返回x
它需要通过pip安装
methodtools


pip install methodtools

我试过编写代码,如果将
@lru\u cache
decorator应用于
\uuu call\uuuu
,它可以正常工作,但对于您的情况,您在初始化时将
\uuuu call\uuuuu
分配给self,因此
\uuu call\uuuuu\uu
的lru版本被添加到
self中,没有实际更改
\uuuu call\uuuu
方法。@Enix如果您指的是正常装饰
\uuuu call\uuuuuu
,那么对一个实例来说是可以的,但一旦有两个实例,缓存就会共享,在一个实例上重置缓存会在另一个实例上重置,因此使用装饰器通常不起作用。(我尽量不提出关于如何拥有实例特定缓存的问题,因为链接的问题涵盖了这一点)