我想要一个可以使用
functools.lru_cache
的函数,但默认情况下不行。我正在寻找一种使用可用于禁用 lru_cache
的函数参数的方法。目前,我有两个版本的函数,一种带有 lru_cache
,一种没有。然后我有另一个函数,它用一个参数包装它们,该参数可用于控制使用哪个函数
def _no_cache(foo):
print('_no_cache')
return 1
@lru_cache()
def _with_cache(foo):
print('_with_cache')
return 0
def cache(foo, use_cache=False):
if use_cache:
return _with_cache(foo)
return _no_cache(foo)
有更简单的方法吗?
您无法从装饰函数内部禁用缓存。但是,您可以通过直接通过
__wrapped__
属性访问该函数来稍微简化代码。
来自文档:
原始底层功能可通过
访问 属性。这对于内省、绕过缓存很有用, 或者用不同的缓存重新包装函数。__wrapped__
演示:
from functools import lru_cache
@lru_cache()
def f(arg):
print(f"called with {arg}")
return arg
def call(arg, use_cache=False):
if use_cache:
return f(arg)
return f.__wrapped__(arg)
call(1)
call(1, True)
call(2, True)
call(1, True)
输出:
called with 1
called with 1
called with 2
为了检查,可以使用
cache_info()
包装函数的方法:
from functools import lru_cache
@lru_cache()
def my_function(foo):
return foo * 2
def cache(foo, use_cache=False):
if use_cache is False:
return my_function.__wrapped__(foo)
return my_function(foo)
print(cache(10, use_cache=True)) # cache miss
print(cache(10, use_cache=True)) # cache hit
print(cache(10, use_cache=False)) # bypass
print(cache(20, use_cache=False)) # bypass
print(my_function.cache_info()) # cache size=1, hit=1, miss=1
打印:
20
20
20
40
CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
您可以使用第二个装饰器来实现缓存控制,并删除该 kwarg。
from functools import wraps
from cachetools import TTLCache, cached
def cache_control(func):
@wraps(func)
def wrapper(*args, **kwargs):
use_cache = kwargs.get('use_cache', True)
if use_cache:
return func(*args, **{k: v for k, v in kwargs.items() if k != 'use_cache'})
else:
return func.__wrapped__(*args, **{k: v for k, v in kwargs.items() if k != 'use_cache'})
return wrapper
并调用双重修饰的原始函数:
mycache = TTLCache(maxsize=settings.CACHE_SIZE, ttl=settings.CACHE_TTL)
@cache_control
@cached(mycache)
def my_function()
pass
# call with cache
my_function(use_cache=True)
#call without cache
my_function(use_cache=False)