为什么 functools.lru_cache 在使用普通方法时不缓存 __call__
Why does functools.lru_cache not cache __call__ while working on normal 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'
这是由于 class 属性和实例属性之间的差异。访问属性时(例如 method
)python 首先检查实例属性。如果您还没有分配给 self.method
它不会找到一个。然后检查class个属性,相当于self.__class__.method
。此函数的值不会通过分配给 self.method
来更改,它只会更新实例属性。
但是,b(1)
变成了 b.__class__.__call__(b, 1)
,它使用 class __call__
和 b.__call__(1)
的原始定义将以与 method
相同的方式缓存,因为它使用 实例 定义。
原来的回答真不错
我附上了问题的另一个解决方案。
methodtools.lru_cache
将如您所愿。
from methodtools import lru_cache
class test:
@lru_cache
def __call__(self, x):
print('__call__', end=' ')
return x
需要通过 pip 安装methodtools
:
pip 安装方法工具
我一直在尝试使 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'
这是由于 class 属性和实例属性之间的差异。访问属性时(例如 method
)python 首先检查实例属性。如果您还没有分配给 self.method
它不会找到一个。然后检查class个属性,相当于self.__class__.method
。此函数的值不会通过分配给 self.method
来更改,它只会更新实例属性。
但是,b(1)
变成了 b.__class__.__call__(b, 1)
,它使用 class __call__
和 b.__call__(1)
的原始定义将以与 method
相同的方式缓存,因为它使用 实例 定义。
原来的回答真不错
我附上了问题的另一个解决方案。
methodtools.lru_cache
将如您所愿。
from methodtools import lru_cache
class test:
@lru_cache
def __call__(self, x):
print('__call__', end=' ')
return x
需要通过 pip 安装methodtools
:
pip 安装方法工具