4

在最近的一期Hacker Newsletter中,链接了这篇关于 Python 装饰器的非常有用的文章。我喜欢这篇文章,并且我认为我理解了大部分装饰器示例。但是,在非装饰器记忆示例中,我对代码感到非常困惑:

def memoize(fn):
    stored_results = {}

    def memoized(*args):
        try:
            # try to get the cached result
            return stored_results[args]
        except KeyError:
            # nothing was cached for those args. let's fix that.
            result = stored_results[args] = fn(*args)
            return result

    return memoized

我对这个函数如何创建一个stored_results附加的持久字典感到困惑。重新阅读后,将其复制/粘贴到我的编辑器中并使用它,并在网上寻求帮助,我仍然不明白语法stored_results[args] = fn(*args)的真正作用。

(1) 文章建议上述代码将返回函数,但现在它会先搜索字典,然后再执行新参数。这是怎么发生的?为什么不stored_results只是本地的memoize?为什么它在memoized返回时不会被销毁?

(2) 链接到其他问题或网络资源来解释此处传递的论点*args也会有所帮助。如果*args是一个参数列表,为什么我们可以使用语法 stored_results[args],当您尝试在列表中索引字典时通常会遇到不可散列的错误?

感谢任何澄清的想法。

4

1 回答 1

5

如果*args是一个参数列表,为什么我们可以使用语法stored_results[args],当您尝试在列表中索引字典时通常会遇到不可散列的错误?

因为它不是一个列表,它是一个元组。列表是可变的,因此您无法在它们上定义有意义的哈希函数。然而,元组是不可变的数据结构。

为什么 stored_results 不只是本地的memoize?为什么它在memoized返回时不会被销毁?

因为memoizememoized共享同名上下文(闭包)。闭包仍然存在,因为memoized持有对它的引用,然后您将其返回并将其分配给全局名称(这是装饰器语句的效果)。通过关闭,所有捕获的值也将保持不变。

于 2012-04-20T01:47:08.007 回答