python functools.wraps裝飾器模塊
阿新 • • 發佈:2017-12-24
aps imp 計時 def 進行 Coding 被調用 這一 import
1 # -*-coding=utf-8 -*- 2 #實現一個函數執行後計算執行時間的功能 3 4 __author__ = ‘piay‘ 5 import time, functools 6 7 8 def foo(): 9 ‘‘‘ 10 定義一個普通函數 11 :return: 12 ‘‘‘ 13 print ‘this is foo‘ 14 15 16 foo() 17 18 ‘‘‘ 19 這裏如果我們需要查看函數執行時間,修改為: 20 ‘‘‘ 21 22 23 deffoo1(): 24 start_time = time.clock() 25 print ‘this is foo1‘ 26 end_time = time.clock() 27 print ‘執行時間為:‘, end_time - start_time 28 29 30 foo1() 31 32 ‘‘‘ 33 如果我們其他的函數也需要執行時間,或者這個函數不需要執行時間,那麽我們就需要復制到其他的函數中去 34 這是一種最差的方法 35 ‘‘‘ 36 37 38 def foo3(): 39 print ‘this is foo3‘ 40 41 42 def timeit(func): 43 ‘‘‘ 44 我們可以考慮重新定義一個函數timeit,將foo的引用傳遞給他, 45 然後在timeit中調用foo並進行計時,這樣,我們就達到了不改動foo定義的目的 46 :param func: 傳入的函數 47 :return: 48 ‘‘‘ 49 start_time = time.clock() 50 func() 51 end_time = time.clock() 52 print ‘used:‘, end_time - start_time53 54 55 timeit(foo3) 56 ‘‘‘ 57 這樣寫修改調用部分的代碼。原本我們是這樣調用的:foo3(),現在變成timeit(foo),這樣的話,如果foo在N處都被調用了, 58 你就不得不去修改這N處的代碼。或者更極端的,考慮其中某處調用的代碼無法修改這個情況,比如:這個函數是你交給別人使用的。 59 ‘‘‘ 60 61 ‘‘‘ 62 想想辦法不修改調用的代碼;如果不修改調用代碼,也就意味著調用foo()需要產生調用timeit(foo)的效果。我們可以想到將timeit賦值給foo, 63 但是timeit似乎帶有一個參數……想辦法把參數統一吧!如果timeit(foo)不是直接產生調用效果, 64 而是返回一個與foo參數列表一致的函數的話……就很好辦了,將timeit(foo)的返回值賦值給foo,然後,調用foo()的代碼完全不用修改! 65 ‘‘‘ 66 67 68 def foo4(): 69 print ‘this is foo4‘ 70 71 72 # 定義一個計時器,傳入一個,並返回另一個附加了計時功能的方法 73 def timeit4(func): 74 # 定義一個內嵌的包裝函數,給傳入的函數加上計時功能的包裝 75 def wrapper(): 76 start_time = time.clock() 77 func() 78 end_time = time.clock() 79 print ‘used:‘, end_time - start_time 80 81 # 將包裝後的函數返回 82 return wrapper 83 84 85 foo_1 = timeit(foo4) 86 ‘‘‘ 87 上面的代碼就類似裝飾器了,可以修改為如下: 88 ‘‘‘ 89 90 91 @timeit4 # 定義上加上這一行與另外寫foo = timeit(foo)完全等價 92 def foo5(): 93 print ‘this is foo5‘ 94 foo5() 95 96 97 ‘‘‘ 98 ----------------------------------------------- 99 使用functools.wraps(func)裝飾器實現功能 100 ‘‘‘ 101 def timeit_3_for_wraps(func): 102 @functools.wraps(func) 103 def wrapper(): 104 start=time.clock() 105 func() 106 end=time.clock() 107 print ‘used:‘,end-start 108 return wrapper 109 110 @timeit_3_for_wraps 111 def foo6(): 112 print ‘this is foo6‘ 113 foo6()
這裏實現一個完整的判斷是否帶參數的裝飾器:
1 # -*-coding=utf-8 -*- 2 __author__ = ‘piay‘ 3 import functools, time 4 ‘‘‘ 5 一個函數執行前打印開始執行,執行完後打印執行完成,記錄執行時間 6 ‘‘‘ 7 8 def log(text): 9 if callable(text): # 參數如果是函數,說明裝飾器不帶參傳過來,text是一個函數 10 @functools.wraps(text) 11 def wrapper(*args, **kwargs): 12 start = time.clock() 13 print ‘這是不帶參數的裝飾器,開始執行‘ 14 f = text(*args, **kwargs) #執行本身的函數 text() 15 end = time.clock() 16 print "結束執行:", end - start 17 return f # 返還原函數 18 return wrapper 19 20 elif not callable(text): # text是參數,不是函數 21 def decarator(func): 22 @functools.wraps(func) 23 def warpper(*args, **kwargs): 24 start = time.clock() 25 print ‘這是不帶參數的裝飾器,開始執行,參數為:‘+text 26 f = func(*args, **kwargs) 27 end=time.clock() 28 print "結束執行:",end-start 29 return f #返還原函數 30 return warpper 31 return decarator 32 else: 33 print ‘請檢查是否正確‘ 34 35 36 @log 37 def add1(x,y): 38 print x+y 39 40 @log(‘222‘) 41 def add2(x,y): 42 print x+y 43 44 add1(1,2) 45 add2(2,3)
執行結果:
D:\Python27\python.exe D:/Python/functools_study/完整的裝飾器.py
這是不帶參數的裝飾器,開始執行
3
結束執行: 5.08444509009e-05
這是不帶參數的裝飾器,開始執行,參數為:222
5
結束執行: 2.49333364995e-05
Process finished with exit code 0
python functools.wraps裝飾器模塊