从函数内部禁用 `functools.lru_cache`

问题描述 投票:0回答:3

我想要一个可以使用

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)

有更简单的方法吗?

python python-decorators functools
3个回答
13
投票

您无法从装饰函数内部禁用缓存。但是,您可以通过直接通过

__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

3
投票

为了检查,可以使用

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)

0
投票

您可以使用第二个装饰器来实现缓存控制,并删除该 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)


© www.soinside.com 2019 - 2024. All rights reserved.