试图理解Python备忘录化代码片段

试图理解Python备忘录化代码片段,python,function,memoization,Python,Function,Memoization,在最近的一期中,链接了关于Python中的装饰器。我喜欢这篇文章,我想我理解了大多数装饰师的例子。但是,在非装饰者备忘录示例中,我对代码感到非常困惑: def memoize(fn): stored_results = {} def memoized(*args): try: # try to get the cached result return stored_results[args] exc

在最近的一期中,链接了关于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
我不知道这个函数如何创建一个持久化的字典
存储的\u结果
,并将其附加到。在重新阅读、将其复制/粘贴到我的编辑器中并使用它,以及在线寻求帮助之后,我仍然不明白
存储的结果[args]=fn(*args)
语法到底在做什么

(1) 本文建议上面的代码将返回函数,但现在它将在执行新参数之前首先搜索字典。这是怎么发生的?为什么
存储的\u结果不只是本地的
记忆
?当返回
已记忆的
时,它为什么不被销毁

(2) 通过
*args
链接到其他问题或web资源,解释此处传递的参数也会很有帮助。如果
*args
是一个参数列表,为什么我们可以使用语法
存储的\u结果[args]
,而通常情况下,您在尝试为列表上的词典编制索引时会遇到不可散列的错误

谢谢你澄清我的想法

如果
*args
是一个参数列表,为什么我们可以使用语法
存储的\u结果[args]
,而通常情况下,您在尝试为列表上的词典编制索引时会遇到不可散列的错误

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

为什么存储的结果不只是本地的
memoize
?当返回
已记忆的
时,它为什么不被销毁


因为
memoize
memoized
共享相同的名称上下文(闭包)。闭包之所以持续存在,是因为
memoized
保存了对它的引用,然后返回它并将其分配给全局名称(这是decorator语句的效果)。通过闭包,所有捕获的值也会保留。

因此,
fn(*args)
将由
args
元素组成的元组推送到函数
fn()
。这是否意味着
storaged\u results
有一个由整个元组索引的条目?在link的例子中,他们对Fibonacci函数这样做。因此,如果我用一个整数参数调用该函数,比如说
6
,字典是否会被扩展为具有类似
{(6):8,…}
的条目?如果是这样的话,这就澄清了一个问题:它假设充满
args
的整个元组将被用作单个记忆键。这仍然让我想知道为什么
存储的结果
会在对新函数的多次调用中持续存在。似乎内部的
记忆的
东西只知道代理的
存储的结果
。Python是否因为内部
memoized
的定义引用了该对象而隐式保持该对象的活动状态?@EMS是的,memoized函数引用了该对象,因此Python不会对其进行垃圾收集。这种带有“自由变量”的函数被称为a,这更有意义,但它看起来相当粗糙。它的读取方式肯定会让人觉得代码应该创建一个范围错误<代码>存储的\u结果
不是全局的,并且没有作为参数传递到
已记忆的
。这是否特定于在其他函数中定义的函数?子函数总是知道父函数的对象吗?我想这更多的是@tobyodavies的评论:闭包的概念是有意义的,但是这个特定函数可以看到非局部的东西似乎是任意的。Python中是否有一些重要的闭包约定需要记住?(我现在在谷歌上搜索这个,所以答案可能是直接而明显的,但我觉得在这里记录下来还是不错的…)