裝飾器

定義:app

  器字表明函數,裝飾器本質是函數;裝飾:裝飾其餘函數,就是爲其餘函數添加附加功能函數

原則:spa

  1.不能修改被裝飾函數的源代碼(在不修改被裝飾函數源代碼的狀況下爲其添加功能)3d

  2.不能修改被裝飾的函數的調用函數,被裝飾函數不知道被裝飾了code

實現裝飾器須要瞭解:blog

  1.函數及變量:內存存儲函數方式與存儲變量同樣:內存中存儲函數體,再指向函數名ip

  2.高階函數內存

a.把一個函數名看成實參傳給另外個函數(在不修改被裝飾函數源代碼的狀況下爲其添加功能)input

b.返回值中包含函數名(不修改函數的調用方式)it

 1 import time
 2 def bar():#bar是這個函數的門牌號
 3     time.sleep(2)
 4     print('in the bar')
 5 def test1(func):#不是裝飾器,是由於函數的調用方式test1(bar)被更改了
 6     start_time=time.time()
 7     func()
 8     stop_time=time.time()
 9     print('the func fun time is %s' % (stop_time-start_time))
10 
11 test1(bar) #func=bar

 運行結果:

  

 1 import time
 2 def bar():#bar是這個函數的門牌號
 3     time.sleep(2)
 4     print('in the bar')
 5 
 6 def test2(func):
 7     print(func)
 8     return func
 9 
10 print(test2(bar))
11 print('--------------------')
12 bar=test2(bar)
13 print('--------------------')
14 bar()

運行結果:

  3.嵌套函數:在已定義的函數內部再定義函數

1 def foo():
2     print('in the foo')
3     def bar():#bar具備局部變量的特性
4         print('in the bar')

 

經過高階函數和嵌套函數實現裝飾器功能:

 1 import time
 2 
 3 def timer(func):#在被裝飾函數以外嵌套裝飾器函數,添加裝飾功能
 4     def deco(*args,**kwargs):#不固定參數參數
 5         start_time=time.time()
 6         result=func(*args,**kwargs)#被裝飾的函數在這運行
 7         stop_time=time.time()
 8         print('the func run time is %s' % (stop_time-start_time))
 9 
10         return result#加入了返回值
11     return deco#timer這個函數返回了deco函數的地址
12 
13 @timer#@timer等於test1=timer(test1):返回了deco函數的內存地址賦給了test1,此時test1是新的test1,這時的test1已經有了裝飾器的功能
14 def test1():
15     time.sleep(3)
16     print('in the test1')
17 
18 @timer#test2=timer(test2),deco=test2
19 def test2(name):
20     time.sleep(3)
21     print('test2:',name)
22     print('in the test2')
23     return 'from test2'#加入了返回,裝飾器內的函數也要加返回
24 
25 test1()
26 print('-----------------')
27 print(test2('tao'))#print打印函數的返回值

運行結果:

  因此說,裝飾器就是將被裝飾函數在裝飾器函數內執行,再將裝飾器函數賦予被裝飾函數名,以後再執行被裝飾函數時就至關於執行了裝飾器函數,即在沒有改變被裝飾函數的源代碼和調用方式的狀況下,實現了裝飾的功能。

 

實現加入參數的裝飾器:

 1 user,passwd='Tao','abc'
 2 def auth(auth_type):#與未加參數的裝飾器區別:裝飾器多加了一個參數,要多嵌套一層函數;auth返回的還是wrapper這個函數
 3     def outer_wrapper(func):#注意加入的參數和func的位置
 4         def wrapper(*args, **kwargs):#auth函數返回out_wrapper,out_wrapper函數返回wrapper,因此auth函數返回的還是wrapper這個函數
 5 
 6             #判斷參數
 7             if auth_type=='local':
 8                 username = input('username:').strip()
 9                 password = input('passwd:').strip()
10 
11                 if user == username and passwd == password:
12                     print('歡迎')
13                     res = func(*args, **kwargs)  #當被裝飾函數有返回值時
14                     return res
15                 else:
16                     exit('錯誤')
17 
18             #判斷參數
19             elif auth_type=='ldap':
20                 print('ldap沒法實現')
21 
22         return wrapper
23 
24     return outer_wrapper
25 
26 
27 
28 def index():
29     print('welcome to index page')
30 
31 @auth(auth_type='local')#auth返回了wrapper這個函數賦給了home
32 def home():
33     print('welcome to home page')
34     return "from home" #加入了返回,裝飾器內的函數也要加返回
35 
36 @auth(auth_type='ldap')#auth返回了wrapper這個函數賦給了bbs
37 def bbs():
38     print('welcome to bbs page')
39 
40 index()
41 print('--------------------')
42 print(home())#打印函數的返回值即from home
43 print('--------------------')
44 bbs()

運行結果:

相關文章
相關標籤/搜索