0

我用我在工作中遇到的一些代码编写了这个简单、人为的示例。我试图更好地理解为什么 slow_function_1 (+ 其装饰器的结构方式)会正确缓存函数结果,但应用于 slow_function_2 的装饰器不会。在这个例子中,我试图在调用方法后访问缓存信息;但是,我一直收到以下错误:AttributeError: 'function' object has no attribute 'cache_info'. 我一直在寻找高低试图解决这个问题,但无济于事。此 AttributeError 为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())

4

1 回答 1

1

现在我盯着它看了很长时间,我认为用装饰器来做这件事是不可能的。您需要一个lru_cache对象来访问缓存和所有这些东西,并且您需要第二个函数在传递给lru_cache对象之前将参数格式化为可散列。装饰器不能同时返回两者,它们不能相互嵌套以使一个功能两全其美。

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())
于 2021-09-12T03:28:23.857 回答