为什么在使用常规方法时functools.lru_cache不缓存__call__ [英] Why does functools.lru_cache not cache __call__ while working on normal methods
问题描述
我一直在按照此答案中的说明,尝试使 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屋!