1. 程式人生 > >python functools.wraps裝飾器模塊

python functools.wraps裝飾器模塊

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 def
foo1(): 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_time
53 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裝飾器模塊