參考鏈接:
從上述回答中的幾個有助於裝飾器理解的 關鍵點:
- 裝飾器發生在
定義
階段而不是執行
階段。 - 裝飾器返回的是一個被裝飾過的
函數定義
。 - 結合第二點理解
now = foo(now)
。
原因:
如果沒有嵌套,實際上裝飾器返回的要麼是原函數的定義,要麼根本不是函數,也就是說函數根本沒有被裝飾。
即使碰巧得到了想要的結果也是裝飾器在定義的階段便運行的,這其實是不應該發生的,因爲這意味着不調用函數,照樣會有輸出,而且效果不能在函數被調用時復現。
代碼說明如下
無嵌套示例:
def foo(func): # 裝飾器內部無嵌套
print ("[INFO]: now exe {}()".format(func.__name__))
return func
@foo
def hello(x):
print ("hello {}!".format(x))
此時直接運行上述代碼是會打印出[INFO]: now exe hello()
的,然而此處並沒有調用hello
如果碰巧在上述代碼末尾加上了hello(x="world")
,那麼將會輸出:
[INFO]: now exe hello()
hello world!
這完全足以以假亂真了,實際情況是定義階段產生了第一條輸出,真正調用時只產生了第二條。
嵌套寫法:
def foo(func): # 裝飾器內部有嵌套
def wrapper(*args, **kwargs):
print ("[INFO]: now exe {}()".format(func.__name__))
return func(*args, **kwargs)
return wrapper
@foo
def hello(x):
print ("hello {}!".format(x))
hello("world")
解釋:
裝飾器等於修改了原函數定義,返回的仍然是函數定義!而不是單純的返回的函數運行結果。
此時再調用被裝飾函數實際執行的是已經被裝飾過的函數(即可以理解爲調用具有裝飾器的函數,該函數的實際定義已經不是你看到的定義,而是被裝飾器修改後的)
一次定義後即可重複使用,就像普通定義函數一般。
個人以爲如果用裝飾器,又不嵌套的寫法是完全有悖裝飾器初衷的,這時大可不必用裝飾器,還不如直接函數調用來的實在。
更多
如果對裝飾器不甚瞭解或者想了解更多,推薦下面的鏈接:爲什麼需要裝飾器