Python成長之路_裝飾器

1、初入裝飾器python

一、首先呢咱們有這麼一段代碼,這段代碼假設是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就返回okredis

二、公司有N個業務部門,1個基礎平臺部門,基礎平臺負責提供底層的功能,如:數據庫操做、redis調用、監控API等功能。業務部門使用基礎功能時,只需調用基礎平臺提供的功能便可。那麼咱們業務部門調用功能的時候只須要。數據庫

f1(值)編程

f2(值)ide

三、公司的運行正在有條不穩的進行,然而有一天呢,你的老大說,我發現了一個問題就是呢業務部調用基礎平臺的功能的時候沒有驗證這樣很差因此呢老大就把工做交給了LOW們,要求增長驗證功能而且業務部門在調用功能的方式不能變函數式編程

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也被開除了url

最後老大把工做交給了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'
單層裝飾器

 

2、好,故事(這個故事是盜取銀角大王的)到此結束咱們開始來看上面的代碼

(1)首先咱們要知道當函數不加括號咱們的函數是不被執行的,它會返回這個函數的內存地址
1 def aaa():
2     print("ok")
3 
4 print(aaa)
5 
6 <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的內存地址,而後return返回函數wra,注意的是f1 = out(f1),沒加括號因此都沒執行,返回wra的時候也沒加括號因此也沒執行,那麼到了這裏這個函數就先暫停咱們結合者調用來看下面的圖:
第一步:請務必分開wra不等於f1而是main等於f1!!下面的f1就等於wra的意思是執行f1函數就等於執行wra函數
image
第二步:
image
最後呢咱們經過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)也只接收了一個參數
1 def out(main):
2     def wra(aaa):
3         print('我進來了')
4         ccc = main(aaa)
5         return ccc
6     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)  #運行一下看看吧呵呵
裝飾參數函數的裝飾器

3、裝飾器的終極進化(多層裝飾器)邏輯比較繞

有一天,變態的老大又找到了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請看圖片,有一句話要牢記這個裝飾器我就把它理解成調用,也就是把須要用的函數傳入到裝飾器作值,從而調用值來執行函數
 
image 
第二步:
image 

 

好到了這裏你們應該明白了吧,不明白的留言,講錯了的請指教謝謝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成爲了…此處省略一百萬個字

做者:北京小遠
出處:http://www.cnblogs.com/bj-xy/ 本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

相關文章
相關標籤/搜索