记住装饰器保持存储的值

时间:2017-06-15 21:58:11

标签: python python-decorators memoization

我有一个看起来像这样的memoization装饰器:

def memoize(obj):
    from functools import wraps
    cache = {}

    @wraps(obj)
    def memoizer(*args, **kwargs):
        if args not in cache:
            cache[args] = obj(*args, **kwargs)
        return cache[args]

    return memoizer

但是,我不确定这个函数是否正常工作,因为我觉得每次调用修饰函数时它都会重新创建cache一个空字典。当我用简单的斐波纳契函数测试它时,它似乎确实记忆正确。那么cache每次都没有重新创建吗?

包含此行的python wiki has a version

cache = obj.cache = {}

所以我不确定这是做什么的。我猜python函数是对象,因此它创建了一个与该函数关联的新属性,并且每次调用该函数时都是公共可用/可用的。

在任一版本中,如果我重复调用该函数,如在递归定义中或仅通过重复调用,如何处理缓存?它是否与功能相关联,它是否成为全球性的"变量,或其他什么?

1 个答案:

答案 0 :(得分:2)

1)为每次调用cache创建一个新的memoize()。但是memoize()只为每个修饰函数调用一次。因此,每个修饰函数都有自己的cache

2)关于cache = obj.cache = {}

函数也是Python中的对象。正如您已经假设的那样,obj.cache = {}将在包装函数上创建一个新属性。包装函数上的本地缓存对象和缓存属性将指向同一个字典。

这不是cache是一个全局变量的人 - 它在memoize函数中是本地的,它是函数的一个属性。

如果你有一个装饰函数f,你可以在全局范围内访问f.cache,如果这是你对全局变量的意思。

如果重复调用修饰函数,它将始终访问特定于修饰函数的cache

解决内部功能而不是“记忆”。

def outer():
    # do not add the decorator here!
    def inner():
        return 5
    if(not hasattr(outer, "inner")):
        # the "@" decorator is only syntactical sugar, 
        # we can simply call the decorator function to wrap another function
        outer.inner = memoize( inner )
    outer.inner()
    return outer.inner()

outer()
outer()