2015-08-24 29 views
2

我剛剛開始使用Python,並且剛剛接觸到裝飾器。我寫了下面的代碼,模仿我所看到的,和它的作品:@decorators在Python中:爲什麼內部定義的函數?

def decorator_function(passed_function): 
    def inner_decorator(): 
     print('this happens before') 
     passed_function() 
     print('this happens after') 
    return inner_decorator 

@decorator_function 
def what_we_call(): 
    print('The actual function we called.') 

what_we_call() 

但後來我寫了這一點,這引發錯誤:

def decorator_function(passed_function): 
    print('this happens before') 
    passed_function() 
    print('this happens after') 

@decorator_function 
def what_we_call(): 
    print('The actual function we called.') 

what_we_call() 

那麼,爲什麼我們需要有內裝飾器函數內部的嵌套函數?它的用途是什麼?僅僅使用第二種語法會不會更簡單?我沒有得到什麼?

有趣的是,這兩個具有相同的(正確)的輸出,但在第二個有錯誤文本爲好,說:「類型錯誤:‘NoneType’對象不是可調用的」

請用語言和例子適合對於剛開始使用Python的人來說,他的第一個編程語言 - 也是OOP的新手! :) 謝謝。

回答

5

的原因是,當你做包裝what_we_call在decorator_function:

@decorator_function 
def what_we_call(): 
    ... 

你在做什麼是:

what_we_call = decorator_function(what_we_call) 

在你第一個例子中它的作品,因爲你不跑inner_function實際上只是初始化它,然後返回新的inner_function(以後在調用裝飾的what_we_call時調用):

def decorator_function(passed_function): 
    def inner_decorator(): 
     print('this happens before') 
     passed_function() 
     print('this happens after') 
    return inner_decorator 

相反,在你的第二個例子中,你要運行在2個之間打印報表和passed_function(what_we_call在我們的例子):

def decorator_function(passed_function): 
    print('this happens before') 
    passed_function() 
    print('this happens after') 

換句話說,你不回的功能之前的例子:你運行

what_we_call = decorator_function(what_we_call) 

的代碼(你可以看到輸出),但隨後decorator_function回報「無」到what_we_call(覆蓋原來的功能),並且當你調用「無」,如果它是Python抱怨的一個函數。

+0

所以decorator_function僅僅是每當調用what_we_cal()時被調用的「引擎」,但inner_decorator是傳回的實際函數?所以我可以通過返回回傳任何東西,只要它是一個函數? – Sindyr

+0

PS:如何格式化評論中的代碼塊? – Sindyr

+0

所以你甚至可以寫這個: 'def decorator_function(passed_function): return other_function' 並且完全修正裝飾函數,是嗎? – Sindyr

3

Python裝飾器基本上只是語法糖。這:

@decorator 
def fn(arg1, arg2): 
    return arg1 + arg2 

變爲這樣:

def fn(arg1, arg2): 
    return arg1 + arg2 
fn = decorator(fn) 

也就是說,一個裝飾基本上接受函數作爲參數,並返回 「東西」;這個「東西」被綁定到裝飾函數的名字上。

在幾乎所有情況下,這個「something」應該是另一個函數,因爲預計fn將是一個函數(並且可能會像調用它一樣)。

相關問題