为什么在使用常规方法时functools.lru_cache不缓存__call__ [英] Why does functools.lru_cache not cache __call__ while working on normal methods

查看:44
本文介绍了为什么在使用常规方法时functools.lru_cache不缓存__call__的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在按照此答案中的说明,尝试使 functools.lru_cache 实例具体化,但在 __ call __ 方法上使用时,其解决方案将失败.

I have been trying to make functools.lru_cache instance specific as described in this answer, but their solution fails when used on the __call__ method.

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 __ 上的缓存甚至不注册已调用的函数,并且不可散列的值也不会引发错误.

So the results of __call__ are not getting cached when wrapped using this method. The cache on __call__ does not even register the function having been called, and unhashable values do not throw errors.

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 (仅更新实例属性)不会更改此函数的值.

This is due to the difference between class attributes and instance attributes. When accessing an attribute (such as method) python first checks for an instance attribute. If you have not assigned to self.method it will not find one. Then class attributes are checked, which is equivalent to self.__class__.method. The value of this function is not changed by assigning to self.method, that only updates the instance attribute.

但是, b(1)变为 b .__ class __.__ call __(b,1),它使用的原始 class 定义> __ call __ b .__ call __(1)将使用与 method 相同的方式进行缓存,因为它使用了 instance 定义.

However, b(1) becomes b.__class__.__call__(b, 1) which uses the original class definition of __call__ and b.__call__(1) will be cached the same way as method since it uses the instance definition.

这篇关于为什么在使用常规方法时functools.lru_cache不缓存__call__的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆