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

7

我希望有一个可以使用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)

有没有更简单的方法来做这件事?

1
你无法从函数内部处理这个 - 如果是缓存命中,函数甚至不会被调用。 - jonrsharpe
1
你所能够正确地发明的一切,只是一个工厂函数,它将返回缓存或未缓存的函数对象(取决于参数),而不是函数结果。 - RomanPerekhrest
RomanPerekhest,为什么我要返回函数对象而不是函数结果呢? - TheStrangeQuark
@TheStrangeQuark,生成对象有各种不同的情况。没有人强迫你扩展“home”代码,这取决于你自己。 - RomanPerekhrest
2个回答

12

您无法在修饰函数内部禁用缓存。不过,您可以通过访问函数的 __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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接