Python:如何忽略functools.lru_cache中的特殊参数?

时间:2018-08-09 12:28:26

标签: python decorator

我要缓存的功能类似于:

def a(x, time='last'):

a(x,y)以外,我对每个y=='last'都具有确定性行为。因此,在调用a(x, 'last')时,我想调用“真实的东西”和其他所有功能的lru_cached函数。

我想这可以通过我自己的装饰器来实现:

def my_lru_cache(func):
    def function_wrapper(*args, **kwargs):
        if kwargs is not None:
            if 'time' in kwargs:
                return func(*args, **kwargs)
            else:
                return what?!?

    return function_wrapper

我完全错了吗?该怎么办?

2 个答案:

答案 0 :(得分:3)

lru_cache()中包装函数,然后在顶部添加装饰器,并通过__wrapped__属性访问原始的未缓存函数,或者更好的是,使用inspect.unwrap() function剥离函数任意数量的装饰器:

from functools import wraps
from inspect import unwrap

def bypass_cache_last_time(func):
    @wraps(func)
    def function_wrapper(*args, **kwargs):
        if not 'time' in kwargs or kwargs['time'] == 'last':
            # Bypass any additional decorators and call function directly
            return unwrap(func)(*args, **kwargs)
        else:
            return func(*args, **kwargs)

        return function_wrapper

并将其用作

@bypass_cache_last_time
@lru_cache()
def some_function(x, time='last'):
    # ...

functools.wraps()装饰器通过重新设置包装器的能力,因为它在包装器上设置了__wrapped__属性。

或者让您的装饰器自己应用lru_cache()装饰器,并在装饰时保留原始功能的副本:

def my_lru_cache(func):
    cached = lru_cache()(func)

    @wraps(func)
    def function_wrapper(*args, **kwargs):
        if not 'time' in kwargs or kwargs['time'] == 'last':
            # call the function directly
            return func(*args, **kwargs)
        else:
            # use the lru_cache-wrapped version
            return cached(*args, **kwargs)

    return function_wrapper

将此用作

@my_lru_cache
def some_function(x, time='last'):
    # ...

答案 1 :(得分:1)

您可以直接致电lru_cache(),以使用func获取lru_cache(<args>)(func)的“包装”版本。然后,您可以从包装器中将其返回:

def my_lru_cache(func):
    caching_func = lru_cache()(func)
    def function_wrapper(*args, **kwargs):        
        if kwargs.get('time') == 'last':
            return func(*args, **kwargs)
        return caching_func(*args, **kwargs)
    return function_wrapper