2016-09-24 80 views
1

编辑:我没有做好解释我的问题。我对关闭如何感到困惑,函数似乎记住了它以前的环境,但通过递归调用它似乎找到了名称的更新值。装饰递归函数

我的困惑通过Thomas Ballinger "Finding closure with closures" talk完美解决:一个可变的

范围在定义被确定,可变值在执行被确定。

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

原题:

装饰上的递归函数工作,而无需任何额外的努力:

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 

在蟒蛇什么机制保证在线路freturn f(n-1)*n点的f装饰版本,而不是到原版的?

我认为一个函数在定义的时候会记住它的上下文(因此,使用闭包,内部函数可以使用来自外部函数的对象)。但是当定义f时,修饰器还没有被应用,所以f里面的功能f是指永久的未修饰版本?显然,我误解了函数范围/上下文规则中的某些内容,但是什么?

+1

更多的是缺乏使其指向其他任何地方的机制。请记住,'@ debug'只是用于定义函数的语法糖,然后调用'f = debug(f)',无论您在哪里寻找'f',您现在都可以获得装饰版本。 – jonrsharpe

回答

2

了Python将查找名称f当函数是执行的事实(和当它编译它),看看它是装饰版本:

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

由于名称f实质上是通过应用装饰器来重新绑定的,也就是f,只要它的名字被查找,它就会被使用。

+0

我明白了。但是,那么闭包中的内部函数呢?一个名字如何根据内部函数定义的时间而不是它的执行来设法链接到一个对象? – max

+0

我的评论的答案是在编辑我的问题。 – max