python functools.wraps装饰器模块

时间:2022-02-11 22:26:39
  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