修饰递归函数

Decorating a recursive function

编辑:我没有很好地解释我的问题。我对如何使用闭包感到困惑,该函数似乎记得它以前的环境,但是通过递归调用它似乎找到了名称的更新值。

我的困惑被Thomas Ballinger "Finding closure with closures" talk完美解决了:

Scope of a variable is determined at definition, value of a variable is determined at execution.

因此无论是递归还是闭包,名称的绑定都是在定义时定义的,但值仍然可以在之后更新。

原问题:

装饰器无需任何额外努力即可处理递归函数:

def debug(f):
    def new_f(*args, **kwargs):
        print('arguments:', *args, **kwargs)
        return f(*args, **kwargs)
    return new_f

@debug
def f(n):
    if n > 1:
        return f(n-1)*n # f refers to the decorated version!
    else:
        return 1

python 中的什么机制确保行 return f(n-1)*n 中的 f 指向 f 的修饰版本而不是原始版本?

我认为函数在定义时会记住它的上下文(这样通过闭包,内部函数可以使用外部函数中的对象)。但是在定义f的时候,装饰器还没有应用,所以f里面函数f不应该引用未装饰的永远的版本?显然,我误解了函数作用域/上下文规则中的某些内容,但是什么?

当函数 执行 时 python 将查找名称 f 的事实(而 不会 编译的时候)看到是装饰版:

>>> f
<function __main__.debug.<locals>.new_f>

由于名称 f 本质上是通过应用装饰器重新绑定的,因此只要查找其名称,就会使用 f