AttributeError: 'function' object has no attribute 'cache_info' with functools.lru_cache + argument formatting decorator discrepancy
AttributeError: 'function' object has no attribute 'cache_info' with functools.lru_cache + argument formatting decorator discrepancy
我 运行 在工作中编写了一些代码的简单、人为的示例。我试图更好地理解为什么 slow_function_1 (+它的装饰器的结构方式)会正确缓存函数结果,但应用于 slow_function_2 的装饰器不会。在这个例子中,我试图在调用方法后访问缓存信息;但是,我始终收到以下错误:AttributeError: 'function' object has no attribute 'cache_info'
。我到处搜索以尝试解决此问题,但无济于事。 slow_function_1.cache_info()
和 slow_function_2.cache_info()
都会引发此 AttributeError
如何查看函数调用之间的缓存?如果有人对 slow_function_1 和 slow_function_2 缓存行为不同的原始问题有任何见解,我也将不胜感激。
提前致谢!
import functools
import time
def format_args(func):
def inner(*args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return func(*formatted_args, **kwargs)
return inner
def formatted_cache(func):
def inner(*args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return functools.lru_cache()(func)(*formatted_args, **kwargs)
return inner
@format_args
@functools.lru_cache
def slow_function_1(a: list, b: bool):
time.sleep(1)
print("executing slow function 1")
return sum(a)
@formatted_cache
def slow_function_2(a: list, b: bool):
time.sleep(1)
print("executing slow function 2")
return functools.reduce((lambda x, y: x*y), a)
example_list = [1,2,3,4,5,6,7,8,9,10,11,12]
example_bool = True
slow_function_1(example_list, example_bool)
print(slow_function_1.cache_info())
slow_function_1(example_list, example_bool)
print(slow_function_1.cache_info())
slow_function_2(example_list, example_bool)
print(slow_function_2.cache_info())
slow_function_2(example_list, example_bool)
print(slow_function_2.cache_info())
现在我盯着它看了好久,我认为用装饰器做这件事真的不可能。您需要一个 lru_cache
对象来访问缓存和所有这些东西,并且您需要第二个函数在传递给 lru_cache
对象之前将参数格式化为可散列的。装饰器不能同时 return 两者,它们也不能相互嵌套以实现两全其美的功能。
def formatted_cache(func):
# first we assume func only takes in hashable arguments
# so cachedfunc only takes in hashable arguments
cachedfunc = functools.lru_cache(func)
# inner formats lists to hashable tuples
# then passes it to cachedfunc
def inner(*args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return cachedfunc(*formatted_args, **kwargs)
# oh no, we can only return one function, but neither is good enough
我认为前进的唯一方法就是接受这些必须在单独的函数中完成,因为 lru_cache
的限制。实际上并没有那么尴尬,只是一个简单的高阶函数,如 map
.
import functools
import time
def formatted_call(func, *args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return func(*formatted_args, **kwargs)
@functools.lru_cache
def slow_function_2(a: list, b: bool):
time.sleep(1)
print("executing slow function 2")
return functools.reduce((lambda x, y: x*y), a)
example_list = [1,2,3,4,5,6,7,8,9,10,11,12]
example_bool = True
formatted_call(slow_function_2, example_list, example_bool)
print(slow_function_2.cache_info())
formatted_call(slow_function_2, example_list, example_bool)
print(slow_function_2.cache_info())
我 运行 在工作中编写了一些代码的简单、人为的示例。我试图更好地理解为什么 slow_function_1 (+它的装饰器的结构方式)会正确缓存函数结果,但应用于 slow_function_2 的装饰器不会。在这个例子中,我试图在调用方法后访问缓存信息;但是,我始终收到以下错误:AttributeError: 'function' object has no attribute 'cache_info'
。我到处搜索以尝试解决此问题,但无济于事。 slow_function_1.cache_info()
和 slow_function_2.cache_info()
如何查看函数调用之间的缓存?如果有人对 slow_function_1 和 slow_function_2 缓存行为不同的原始问题有任何见解,我也将不胜感激。
提前致谢!
import functools
import time
def format_args(func):
def inner(*args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return func(*formatted_args, **kwargs)
return inner
def formatted_cache(func):
def inner(*args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return functools.lru_cache()(func)(*formatted_args, **kwargs)
return inner
@format_args
@functools.lru_cache
def slow_function_1(a: list, b: bool):
time.sleep(1)
print("executing slow function 1")
return sum(a)
@formatted_cache
def slow_function_2(a: list, b: bool):
time.sleep(1)
print("executing slow function 2")
return functools.reduce((lambda x, y: x*y), a)
example_list = [1,2,3,4,5,6,7,8,9,10,11,12]
example_bool = True
slow_function_1(example_list, example_bool)
print(slow_function_1.cache_info())
slow_function_1(example_list, example_bool)
print(slow_function_1.cache_info())
slow_function_2(example_list, example_bool)
print(slow_function_2.cache_info())
slow_function_2(example_list, example_bool)
print(slow_function_2.cache_info())
现在我盯着它看了好久,我认为用装饰器做这件事真的不可能。您需要一个 lru_cache
对象来访问缓存和所有这些东西,并且您需要第二个函数在传递给 lru_cache
对象之前将参数格式化为可散列的。装饰器不能同时 return 两者,它们也不能相互嵌套以实现两全其美的功能。
def formatted_cache(func):
# first we assume func only takes in hashable arguments
# so cachedfunc only takes in hashable arguments
cachedfunc = functools.lru_cache(func)
# inner formats lists to hashable tuples
# then passes it to cachedfunc
def inner(*args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return cachedfunc(*formatted_args, **kwargs)
# oh no, we can only return one function, but neither is good enough
我认为前进的唯一方法就是接受这些必须在单独的函数中完成,因为 lru_cache
的限制。实际上并没有那么尴尬,只是一个简单的高阶函数,如 map
.
import functools
import time
def formatted_call(func, *args, **kwargs):
formatted_args = [tuple(x) if type(x) == list else x for x in args]
return func(*formatted_args, **kwargs)
@functools.lru_cache
def slow_function_2(a: list, b: bool):
time.sleep(1)
print("executing slow function 2")
return functools.reduce((lambda x, y: x*y), a)
example_list = [1,2,3,4,5,6,7,8,9,10,11,12]
example_bool = True
formatted_call(slow_function_2, example_list, example_bool)
print(slow_function_2.cache_info())
formatted_call(slow_function_2, example_list, example_bool)
print(slow_function_2.cache_info())