You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

functools.lru_cache搭配装饰器报cache_info属性错误及缓存差异求解

问题原因分析

1. 两个函数缓存行为差异的原因

装饰器的执行顺序是从下往上叠加,@format_args @functools.lru_cache def slow_function_1等价于slow_function_1 = format_args(functools.lru_cache(slow_function_1))。运行时传入的列表参数会先被format_args转为可哈希的元组,再传给lru_cache包装的函数,参数满足可哈希要求因此可以正常缓存。
而slow_function_2的缓存失效是因为formatted_cache的实现逻辑错误:原代码中每次调用slow_function_2时,都会执行functools.lru_cache()(func)新建一个全新的lru_cache包装实例,每个实例的缓存空间独立,每次调用都相当于用全新的缓存实例执行函数,自然无法复用之前的缓存结果。

2. AttributeError报错的原因

你自定义的两个装饰器返回的都是内部的inner函数,默认情况下inner不会继承被包装函数的任何属性,lru_cache附加的cache_info、cache_clear等方法都被外层的inner屏蔽了,所以调用时会提示找不到对应属性。

修复方案

需要修改两个自定义装饰器:

  1. 用functools.wraps透传被包装函数的属性
  2. 调整formatted_cache的实现,在装饰器加载时就初始化lru_cache实例,不要每次调用都新建
    修改后的可运行代码如下:
import functools
import time

def format_args(func):
    # 透传被包装函数的属性
    @functools.wraps(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):
    # 装饰器加载时就初始化lru_cache,全局仅创建一次
    cached_func = functools.lru_cache()(func)
    @functools.wraps(func)
    def inner(*args, **kwargs):
        formatted_args = [tuple(x) if type(x) == list else x for x in args]
        # 复用同一个缓存实例
        return cached_func(*formatted_args, **kwargs)
    # 显式绑定lru_cache的方法供外部调用
    inner.cache_info = cached_func.cache_info
    inner.cache_clear = cached_func.cache_clear
    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())

运行后两个函数都只会执行1次,第二次调用直接命中缓存,cache_info也可以正常输出缓存命中统计信息。

内容的提问来源于stack exchange,提问作者cadeaudecheval

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:39:00