一、初入裝飾器 1、首先呢我們有這麼一段代碼,這段代碼假如是N個業務部門的函數 1 def f1(aaa): 2 print('我是F1業務') 3 if aaa == 'f1': 4 return 'ok' 5 6 def f2(aaa): 7 print('我是F2業務') 8 if aaa =
一、初入裝飾器
1、首先呢我們有這麼一段代碼,這段代碼假如是N個業務部門的函數
1 def f1(aaa): 2 print('我是F1業務') 3 if aaa == 'f1': 4 return 'ok' 5 6 def f2(aaa): 7 print('我是F2業務') 8 if aaa == 'f2': 9 return 'ok'業務代碼這裡呢也就是當我們調用上面的函數的時候,傳入值給aaa,當aaa的值等於f1或者f2就返回ok
2、公司有N個業務部門,1個基礎平臺部門,基礎平臺負責提供底層的功能,如:資料庫操作、redis調用、監控API等功能。業務部門使用基礎功能時,只需調用基礎平臺提供的功能即可。那麼我們業務部門調用功能的時候只需要。
f1(值)
f2(值)
3、公司的運行正在有條不穩的進行,然而有一天呢,你的老大說,我發現了一個問題就是呢業務部調用基礎平臺的功能的時候沒有驗證這樣不好所以呢老大就把工作交給了,要求增加驗證功能並且業務部門在調用功能的方式不能變
Low A,這個A呢他是這麼做的
他呢跟各個做基礎功能的人協調,要求在自己的代碼上加入驗證模塊,那麼這樣呢整個的基礎平臺就不需要更改,結果,Low A當天就被開除了……
Low B,這個B呢一看A都被開除了不行上面的方法不行哪就換一個
1 def f1(aaa): 2 #驗證代碼 3 #驗證代碼 4 print('我是F1業務') 5 if aaa == 'f1': 6 return 'ok' 7 8 def f2(aaa): 9 #驗證代碼 10 #驗證代碼 11 print('我是F2業務') 12 if aaa == 'f2': 13 return 'ok'LowB
這家伙呢在每個功能前面加入了驗證代碼,然後過了兩天Low B也被開除了
最後老大把工作交給了Low C
Low C呢總結了兩個Low的教訓他是這麼乾的
1 #驗證函數 2 def verify(): 3 # 驗證1 4 # 驗證2 5 # 驗證3 6 pass 7 8 def f1(aaa): 9 verify(): 10 print('我是F1業務') 11 if aaa == 'f1': 12 return 'ok' 13 14 def f2(aaa): 15 verify(): 16 print('我是F2業務') 17 if aaa == 'f2': 18 return 'ok'Lowc
他呢把驗證功能的,寫成了一個函數然後,每個業務模塊來去調用老大看見了LowC的實現方式,嘴角露出了一絲微笑,並且與LowC聊了個天老大說:寫代碼要遵循開發封閉原則,雖然在這個原則是用的面向對象開發,但是也適用於函數式編程,簡單來說,它規定已經實現的功能代碼不允許被修改,但可以被擴展,即:
- 封閉:已實現的功能代碼塊
- 開放:對擴展開發
如果將開放封閉原則應用在上述需求中,那麼就不允許在函數 f1 、f2的內部進行修改代碼,老闆就給了Low C一個實現方案:
裝飾器(單層裝飾器)
1 def out(main): 2 def wra(): 3 # 驗證1 4 # 驗證2 5 # 驗證3 6 return xxx 7 return wra 8 9 @out 10 def f1(aaa): 11 print('我是F1業務') 12 if aaa == 'f1': 13 return 'ok' 14 15 @out 16 def f2(aaa): 17 print('我是F2業務') 18 if aaa == 'f2': 19 return 'ok'單層裝飾器
二、好,故事(這個故事是盜取銀角大王的)到此結束我們開始來看上面的代碼
(1)首先我們要知道當函數不加括弧我們的函數是不被執行的,它會返回這個函數的記憶體地址def aaa():
print("ok")
print(aaa)<function aaa at 0x0000000000B6AC80>
(2)然後我們來解釋一下@out
@out就等於f1 = out(f1)
什麼意思呢@out是python語法中的一個簡寫,他的用處就是針對裝飾器來去做的,我們看下麵的例子,將@out替換成
f1 = out(f1)1 def out(main): 2 def wra(aaa): 3 print('我進來了') 4 ccc = main(aaa) 5 return ccc 6 return wra 7 8 def f1(aaa): 9 print('我是F1業務') 10 if aaa == 'f1': 11 return 'ok' 12 13 f1 = out(f1) 14 15 s1 = 'f1' 16 17 ff1 = f1(s1) 18 print(ff1)轉換後
(3)我們來解釋下out函數,對於out來說他首先接收一個值,從上面可以看出他接收的值是f1,f2的記憶體地址,然後接收後將值返回給函數wra,註意的是f1,f2都沒加括弧所以都沒執行,返回wra的時候也沒加括弧所以也沒執行,那麼到了這裡這個函數就先暫停我們結合者調用來看下麵的圖:第一步:請務必分開wra不等於f1而是main等於f1!!下麵的f1就等於wra的意思是執行f1函數就等於執行wra函數第二步:最後呢我們通過python語法塘,將f1 = out(f1) 變成@out就變成了之前我們看到的代碼1 def out(main): 2 def wra(aaa): 3 print('我進來了') 4 ccc = main(aaa) 5 return ccc 6 return wra 7 8 @out 9 def f1(aaa): 10 print('我是F1業務') 11 if aaa == 'f1': 12 return 'ok' 13 14 15 s1 = 'f1' 16 ff1 = f1(s1) 17 print(ff1)完整單層裝飾器友情提示:
在此請將之前的練習一下並且熟知其中的原理再進行下麵的學習,大神除外(4)裝飾器裝上含有參數的函數,有同學可能測試了一下說,我把函數f1的參數變成了多個,裝飾器就報錯了,那是怎麼回事呢,原因很簡單,因為wra首先他只能接收一個參數,並且ccc = main(aaa)也只接收了一個參數def out(main):
def wra(aaa):
print('我進來了')
ccc = main(aaa)
return ccc
return wra既然知道了原因那麼我們就給他改改數位寶貝超進化…:
1 def out(main): #這裡就不多解釋了跟上面一樣 2 def wra(*aaa,**aa): #這裡呢變成了啥是不是可以接收各種的參數了 3 print('我進來了') 4 ccc = main(*aaa,**aa) #這裡呢也可以給f1各種參數 5 return ccc 6 return wra 7 8 @out 9 def f1(*af1): 10 print('我是F1業務') 11 print(af1[0]) #給大家測試用的 12 print(af1[1]) 13 if af1[0] == 'f1': 14 return 'ok' 15 16 s1 = 'f1' 17 ff1 = f1(s1,'我是參數2') #傳入了兩個值s1和我是參數2' 18 print(ff1) #運行一下看看吧呵呵裝飾參數函數的裝飾器
三、裝飾器的終極進化(多層裝飾器)邏輯比較繞
有一天,變態的老大又找到了Low C說你的裝飾器練習的咋樣了,Low C說:經過老大的調教,我已經練習的差不多了,這個時候老大陰陰的呵呵一笑,好,這樣我呢又有個需求要你給我改改,我現在呢想在驗證之後呢添加一個歡迎功能,這個功能呢,我們業務線的功能想要添加就添加先要不添加就不添加,要記住封閉原則哦0.0……….
第二天Low C找到了老大說,大哥啊您晚上還是來我家教教我吧,真心的不知道啊0.0,,,於是老大就去了Low C的家裡經過一場風雲(此次省略一萬個字)0.0老大提供了另外的參考代碼:
1 def ds(): 2 print('ok我是歡迎信息1') 3 4 def ss(): 5 print('ok我是歡迎信息2') 6 7 8 def fill(*ill): 9 def out(main): 10 def wra(*waa,**wad): 11 ill[0]() 12 ill[1]() 13 ccc = main(waa[0]) 14 return ccc 15 return wra 16 return out 17 18 19 @fill(ds,ss) 20 def f1(aaa): 21 print('我是F1業務') 22 if aaa == 'f1': 23 return 'ok' 24 25 26 c1 = f1('f1') 27 print(c1)老大的代碼
哈哈看不懂了吧(大神除外)來吧我們分開來看就知道了第一步:還是先解釋一下裝飾器fill請看圖片,有一句話要牢記這個裝飾器我就把它理解成調用,也就是把需要用的函數傳入到裝飾器做值,從而調用值來執行函數第二步:
好到了這裡大家應該明白了吧,不明白的留言,講錯了的請指教謝謝O(∩_∩)O~~,那麼有的小伙伴要問了,這尼瑪不對啊,為毛我把@fill(ds,ss)變成@fill(ss)就報錯了呢?
我們分析一下問題,主要的原因呢就是def wra函數下麵執行了 ill[1]報錯了,因為這裡*ill只有一個參數那麼避免呢,看我的終極大招:
1 def ds(): 2 print('ok我是歡迎信息1') 3 def ss(): 4 print('ok我是歡迎信息2') 5 6 def fill(*ill): 7 def out(main): 8 def wra(*waa,**wad):#這裡加個判斷不就完了麽 O(∩_∩)O哈哈~ 9 if len(ill) != '0': 10 for i in range(0,len(ill)): 11 ill[i]() 12 ccc = main(waa[0]) 13 return ccc 14 return wra 15 return out 16 17 @fill(ss,ds) 18 def f1(aaa): 19 print('我是F1業務') 20 if aaa == 'f1': 21 return 'ok' 22 23 @fill() #你看這裡沒參數吧 24 def f2(aaa): 25 print('我是F2業務') 26 if aaa == 'f2': 27 return 'ok' 28 29 c1 = f1('f1') 30 print(c1) 31 c2 = f2('f2') 32 print(c2)終極大招-多層裝飾器
#運行下試試吧等等!最後老大和Low C成為了…此處省略一萬個字