python - 为什么 functools.lru_cache 在处理普通方法时不缓存 __call__

标签 python caching magic-methods

我一直在尝试使 functools.lru_cache 实例具体化,如 this answer 中所述。 ,但他们的解决方案在 __call__ 方法上使用时失败。

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

因此,使用此方法包装时,__call__ 的结果不会被缓存。 __call__ 上的缓存甚至不会注册已调用的函数,并且不可散列的值不会引发错误。

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'

最佳答案

这是由于类属性和实例属性之间的差异造成的。当访问一个属性(例如method)时,Python 首先检查实例属性。如果您还没有分配给 self.method ,它将找不到。然后检查类属性,相当于self.__class__.method。此函数的值不会通过分配给 self.method 来更改,只会更新实例属性。

但是,b(1) 变为 b.__class__.__call__(b, 1),它使用 的原始 class 定义>__call__b.__call__(1) 将以与 method 相同的方式进行缓存,因为它使用实例定义。

关于python - 为什么 functools.lru_cache 在处理普通方法时不缓存 __call__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53423121/

相关文章:

php - 在 PHP 中删除 header

python - 我怎样才能覆盖魔术方法?

python - 这是定义和使用 Python 异常的合适方法吗?

python - scipy.signal.convolve 中来自黎曼和的人工制品

java - Hibernate - EhCache - 缓存关联/集/集合的哪个区域?

java - 寻找简单的 Java 内存缓存

python - 如何使用 tkinter 在 python 中加密文本

python - 通过使用 pandas 在时间序列中将值分配给先前的 NaN 来回填值

python - 为什么显式调用魔术方法比 "sugared"语法慢?

python - 在类上定义魔法方法