python裝飾器測試與理解
阿新 • • 發佈:2018-12-18
第一,裝飾器基礎語句
# 這是一個基本的裝飾器測試檔案
def deco(func):
def mod():
func()
print("I'm mod")
#mod函式在接收的func函式基礎上,後置增加了print功能
return mod
# 將func拓展為mod後,返回新函式mod。
# 這,就是本deco函式的使命。
# 所以假設main函式如下:
def main():
print("I'm main")
pass
# 則可以有:
a = deco(main) # 滿足deco的引數要求,使其完成使命
a()
# 輸出結果為:
#I'm main
#I'm mod
# 鑑於deco(main)返回的本質是一個函式,甚至可以有:
deco(main)()
# 輸出結果同樣為:
#I'm main
#I'm mod
第二,它是不是裝飾器?裝飾器的執行邏輯是什麼?
# 裝飾器的執行邏輯
def deco(func):
print("I'm deco")
def mod():
print("I'm mod")
pass
return func
#這一次將func原樣返回,mod也未對func作修改。
def main():
print ("I'm main")
a = deco(main)
a()
# 執行結果為:
# I'm deco
# I'm main
# I'm main
# 為什麼deco在前?
# 因為a = deco(main)本身也產生輸出,而a()產生的輸出只有一句
# 不信試試這個:
a()
deco(main)
# 輸出結果為:
# I'm main 由a()生成
# I'm deco 由deco函式生成
#總結:
# 1.裝飾器一般分內外2層,才能達到‘裝飾’的目的。
# 2.內層必須對其對func函式有所操作,否則無法起到
# ‘裝飾器的作用’。
# 3.a()的本質,是執行且僅執行一個函式,
# 就是deco返回的那個函式。
第三,@語法糖
標準的@語法糖
# @語法糖
def deco(func):
def mod():
func()
print("I'm mod")
return mod
@deco
def main():
print("I'm main")
main()
# 最終輸出為:
# I'm main
# I'm mod
# @deco這一行語句,實現瞭如下的基本功能:
# 1.實現了deco(main)這條語句
# 2.實現了將deco(main)賦值給一個也叫main的變數。
# 這相當於a=a+5。 a+5的值,完成了對原來a的覆蓋
# 綜上,@deco這一句,相當於,且僅相當於main = deco(main)
# 這樣寫的好處:
# 1.沒有改變main的呼叫方法。(儘管內部新main替換了老main)
# 2.沒有改變原main函式的內部性質。(依然可以打印出I'm main)
# 以上也是一個良好裝飾器的必備特質。例如本例中def的deco
# ,就具備這樣的特質
@語法糖的執行邏輯
# @語法糖的執行邏輯
def mod2(func):
func()
print("I'm mod2")
return mod2
@mod2
def main2():
print("I'm main2")
# main2()
# 以上是正常程式,並作了2處改動:
# 1.這一次我沒有呼叫main2(),將它註釋掉了。
# 2.原本deco函式內還定義了一層mod,這次將deco外殼刪掉
# 只留下了mod
#最終輸出:
# I'm main2
# I'm mod2
# 那麼@mod2,相當於執行了一次mod2內的所有語句。注意,
# 這是在沒有進行main2()語句呼叫時,就執行過一次的。
# 參考‘它是不是裝飾器?’的內容,相當於執行了mod2(main2)這
# 一語句。
# 下面,你可以試試將mian2()的註釋去掉,看看會發生什麼。
帶返回值的@語法糖
# 帶引數的語法糖
def deco(func):
def mod():
temp = func()
print("I'm mod")
return temp
return mod
@deco
def main():
print("I'm main")
return "I'm main return"
a = main()
print('----分割線')
print(a)
# 最終輸出:
# I'm main
# I'm mod
# ----分割線
# I'm main return
# 裝飾器是圍繞原函式服務的。本例中,因為main多了return語句,所以
# 裝飾器應當為保留return 內的資訊,而作出改變。在本例中,多了
# return temp及其配合語句temp = func(),來實現引數傳遞。傳遞線路為:
# 老main函式的'I'm main return' ,通過func(),傳遞給temp,
# 由temp返回給mod函式,mod函式加上了其它拓展後,新函式mod又
# 寫覆蓋給新main函式,使return在新main函式中實現。
帶引數的@語法糖
# 帶引數的語法糖
def deco(func):
def mod(arg1, arg2):
temp = func(arg1, arg2)
print("I'm mod")
return temp
return mod
@deco
def main(a, b):
print(a + b)
return "I'm main return"
a = main(1, 1)
print(a)
# 最終輸出:
# 2
# I'm mod
# I'm main return #這一句由print(a)輸出
# 比較簡單,還是圍繞main作裝飾器修改。當def mian時,
# 出現a,b兩個引數時,deco中的mod函式,也應當對應出現
# 兩個引數,這裡取名為arg1, arg2。最終main(1,1)
# 呼叫時,既完成了1+1的操作,也完成了輸出"I'm mod"的操作。
帶可變引數的@語法糖
# 帶引數的語法糖
def deco(func):
def mod(*x1, **x2):
temp = func(*x1, **x2)
print("I'm mod")
return temp
return mod
@deco
def main(a, b, c, d):
print(a + b + c + d)
return "I'm main return"
a = main(1, 1, 1, 1)
print(a)
# 最終輸出:
# 4
# I'm mod
# ----分割線
# I'm main return #這一句由print(a)輸出
# 依舊,當main變為4個引數時,我們對裝飾器作被動修改。當def mian時,
# 但程式設計師想偷懶了,索性在def mod時,修改引數為*x1和**x2,大功告成!