python装饰器参数使用函数中的变量进行包装

标签 python python-decorators

我正在寻找一种方法来创建一个装饰器,使其具有一个函数参数,该函数参数实际上使用传递给函数的变量来包装它。

例如,假设我有

@cache_decorator("my_key_{}".format(foo))
def my_function(foo, bar):
    pass

@cache_decorator("another_key_{}_{}".format(foo, bar)
def another_function(user, foo, bar):
    pass

目标是编写一个缓存包装器。装饰器将需要缓存键,但该键将包含传递给函数的变量,并且对于它包装的每个函数都是不同的。

理想情况下,这可以让装饰器检查给定键的缓存值,如果未找到,则执行该函数以获取该值并将其缓存。这样,如果该值在缓存中,它就不会执行创建该值的代码(即 my_function)。如果未找到,则执行 my_function 并将结果存储在缓存中并返回。

另一种选择类似于 block :

def my_function(foo, bar):
    cache_value("my_key_{}".format(foo),{block of code to generate value that is only called if necessary})

在 Objective-C 或 js 中,这将是一个 block ,因此我可以保持本地定义和可变的值生成,但仅在必要时执行。我对 python 太陌生了,无法完全掌握如何使用它的闭包版本来做到这一点。

谢谢!

更新
虽然下面的解决方案适用于装饰器,但我最终选择了类似 block 的路线,因为需要额外的元数据附加到每个缓存条目以确保它可以正确失效。将此元数据定义为值生成(而不是在缓存函数内部)更易于维护。这看起来像:

def my_function(foo, bar):
    def value_func():
        return code_to_generate_value_using_foo_bar

    return get_set_cache(key, value_func, ...)

def get_set_cache(key, value_function, ...):
    value = cache.get(key)
    if value is None:
        value = value_function()
        cache.set(key, value)
    return value

最佳答案

你可以让你的包装器获得一个关键的构建函数:

@cache_w_keyfunc(lambda foo, bar: (bar,))
def my_function(foo, bar):
    pass

@cache_w_keyfunc(lambda user, foo, bar: (foo, bar))
def another_function(user, foo, bar):
    pass

key 生成器应该返回可哈希的东西,例如字符串元组。如果它们不可哈希,例如列表,也许可以将它们转换为字符串。

此 key 构建函数获取与函数本身相同的参数并返回要使用的 key 。

def cache_w_keyfunc(keyfunc):
    def real_decorator(func):
        func.cache = {}
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # Create the key now out of the wrapped function's name and the given keys:
            key = (func.__name__, keyfunc(*args, **kwargs))
            try:
                return func.cache[cache_key]
            except KeyError:
                value = func(*args, **kwargs)
                func.cache.set(cache_key, value)
                return value
        return wrapper
    return real_decorator

关于python装饰器参数使用函数中的变量进行包装,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18790270/

相关文章:

python - 我可以装饰一个显式函数调用吗,比如 np.sqrt()

python - 如何访问装饰器属性?

python - 在 Python 中连接可变数量的列表

python - 创建动态图 python NetworkX

python - scikit-learn 的逻辑回归在打印输出时给出关键错误

python - 自定义属性行为

python - 检测路由是否不是最外层/错误的 Flask 装饰器的 "order"

python - 为什么在元类派生自ABCMeta的类中需要使用@abstractmethod?

python - 出现 Python 异常时 PyObject_CallObject 的正确返回是什么?

python - 从源代码安装 python3.5 后如何修复 virtualenv 的 python pip 段错误(核心转储)响应