如何根据Python函数返回值控制缓存,不缓存返回None的调用结果
Python 实现仅缓存非指定值的lru_cache方案
方案1:通用自定义条件缓存装饰器(Python 3.9+)
该方案完全兼容原生functools.lru_cache的所有参数,可自定义配置不需要缓存的返回值列表:
from functools import lru_cache, wraps def conditional_lru_cache(exclude_values=(None,), **lru_kwargs): cache_decorator = lru_cache(**lru_kwargs) def decorator(func): wrapped = cache_decorator(func) @wraps(func) def inner(*args, **kwargs): result = wrapped(*args, **kwargs) # 返回值属于排除列表时删除本次缓存 if result in exclude_values: wrapped.cache_delete(*args, **kwargs) return result # 透传原生lru_cache的管理方法 inner.cache_info = wrapped.cache_info inner.cache_clear = wrapped.cache_clear inner.cache_delete = wrapped.cache_delete return inner return decorator
使用方式和原生装饰器一致:
@conditional_lru_cache(maxsize=128, exclude_values=(None,)) def my_fun(link): res = fetch_data(link) return res
方案2:Python 3.9以下兼容版本
3.9版本才新增cache_delete方法,低版本可通过操作缓存的底层字典实现相同效果:
from functools import lru_cache, wraps, _make_key def conditional_lru_cache(exclude_values=(None,), **lru_kwargs): cache_decorator = lru_cache(**lru_kwargs) def decorator(func): wrapped = cache_decorator(func) typed = lru_kwargs.get('typed', False) @wraps(func) def inner(*args, **kwargs): # 手动构造缓存key key = _make_key(args, kwargs, typed=typed) result = wrapped(*args, **kwargs) if result in exclude_values: wrapped.cache.pop(key, None) return result inner.cache_info = wrapped.cache_info inner.cache_clear = wrapped.cache_clear return inner return decorator
极简临时方案
如果仅需要单次使用,不想封装装饰器,也可以直接手动控制缓存:
from functools import lru_cache # 先初始化缓存装饰器 cached_fetch = lru_cache(maxsize=128)(fetch_data) def my_fun(link): res = cached_fetch(link) if res is None: # 无效结果直接删除缓存 cached_fetch.cache_delete(link) return res
补充说明:如果使用Python 3.9+的functools.cache(无大小限制的lru_cache),只需要把上述代码中的lru_cache替换为cache即可实现相同逻辑,也支持自定义排除值。
内容的提问来源于stack exchange,提问作者sophros
相关产品推荐
相关产品推荐

