2016-09-24 70 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