2014-12-07 95 views
36
def make_bold(fn): 
    return lambda : "<b>" + fn() + "</b>" 

def make_italic(fn): 
    return lambda : "<i>" + fn() + "</i>" 

@make_bold 
@make_italic 
def hello(): 
    return "hello world" 

helloHTML = hello() 

輸出:"<b><i>hello world</i></b>"裝飾的執行順序

我大致瞭解關於裝飾,以及它如何在大多數例子是一個工作。

在這個例子中,有2個。從輸出看來,@make_italic似乎首先執行,然後@make_bold

這是否意味着對於裝飾函數,它將首先運行函數,然後移動到其他裝飾器的頂部?像@make_italic先是@make_bold,而不是相反。

那麼這意味着它與大多數編程語言中的自頂向下方法的規範不同?只是爲了裝飾者的這種情況?或者我錯了?

+2

是的,它從下往上傳遞結果到下一個 – 2014-12-07 11:28:37

回答

58

裝飾者包裝他們裝飾的功能。所以make_bold修飾了裝飾者make_italic的結果,其中裝飾了hello功能。

@decorator語法實際上只是語法糖;以下內容:

@decorator 
def decorated_function(): 
    # ... 

如確實執行:

def decorated_function(): 
    # ... 
decorated_function = decorator(decorated_function) 

替換原始decorated_function對象與任何decorator()返回。

堆疊裝飾器重複該過程向外

所以你的樣品:

@make_bold 
@make_italic 
def hello(): 
    return "hello world" 

可擴展到:

def hello(): 
    return "hello world" 
hello = make_bold(make_italic(hello)) 

當你調用hello()現在,您呼叫的make_bold()返回的對象,真的。 make_bold()返回lambda,它調用函數make_bold包裝,這是返回值make_italic(),這也是一個lambda,它調用原始hello()。展開所有這些調用你:

hello() = lambda : "<b>" + fn() + "</b>" # where fn() -> 
    lambda : "<i>" + fn() + "</i>" # where fn() -> 
     return "hello world" 

所以輸出變成:

"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>" 
+0

我的理解開始。但是這是否意味着在這種情況下有2個包裝器時,IDE會自動檢測幷包裝第一個包裝器的結果?因爲我認爲'@make_bold #make_bold = make_bold(hello)' '@make_italiC#make_italic = make_italic(hello)'?我不確定是否基於此,它會包裝第一個結果。或者對於這兩個包裝器的情況,IDE將使用'make_bold(make_italic(hello))'來代替我分享的內容。 – Newbie 2014-12-07 11:38:03

+0

@Newbie:你的IDE在這裏什麼也不做;它是* Python *的包裝。我在最後一個示例中展示了make_bold()包裝'make_italic()'的輸出,該輸出用於包裝'hello',所以相當於'make_bold(make_italic(hello))'。 – 2014-12-07 11:40:41

+0

您能否提供此代碼的版本而不使用lambda?我曾嘗試.format但不起作用。爲什麼在這個例子中使用lambda?我試圖理解lambda以及它在這個例子中是如何工作的,但仍然有問題。我得到的lambda就像一行函數,與def函數的規範相比,它可以很容易地傳遞? – Newbie 2014-12-07 12:20:38