装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
在编程过程中我们会调用许多函数,例如:
def foo(): print('this is foo') foo() def bar(): print('this is bar') bar()
但现在我们的需求是得到函数运行所需的时间:
import time def foo(): start = time.time() print("this is foo.") time.sleep(2) #因为此函数运行太快所以加个延时 end = time.time() print('spend %s'%(end-start)) foo() def bar(): start = time.time() print("bar..........") time.sleep(2) end = time.time() print('spend %s' % (end - start)) bar()
虽然以上按要求做出来了,但是却有重复的代码,为了解决重复代码,如下:
import time def foo(): print('foo........') time.sleep(2) def bar(): print("bar&&&&&&&&") time.sleep(2) def show_time(f): start = time.time() f() end = time.time() print('spend %s'%(end-start)) show_time(foo) show_time(bar) #输出: foo........ spend 2.0001730918884277 bar&&&&&&&& spend 2.000176429748535
这个挺好的,但是吧,如果我们要求最后运行的函数就是本函数比如foo()而不是show_time(foo),那么就:
import time def show_time(f): def wrapper(): start = time.time() f() end = time.time() print('spend %s'%(end-start)) return wrapper def foo(): print('foo..........') time.sleep(2) foo = show_time(foo) foo() #输出: foo.......... spend 2.0007383823394775
python里有个更简便的做法,加@:
import time def show_time(f): def wrapper(): start = time.time() f() end = time.time() print('spend %s'%(end-start)) return wrapper @show_time def foo(): print('foo..........') time.sleep(2) foo()
带参数的被修饰函数:
import time def show_time(f): def wrapper(a,b): start = time.time() f(a,b) end = time.time() print('spend %s'%(end-start)) return wrapper @show_time def add(a,b): print(a+b) time.sleep(2) add(1,2) #输出:3 可变长加法 def show_time(f): def wrapper(*a,**b): start = time.time() f(*a,**b) end = time.time() print('spend %s'%(end-start)) return wrapper @show_time def add(*a,**b): sum = 0 for i in a: sum+=i print(sum) time.sleep(2) add(1,2,4,5,6) #输出:18
装饰器还有更大的灵活性,例如带参数的装饰器:在上面的装饰器调用中,比如@show_time,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。
import time def time_logger(flag=0): def show_time(f): def wrapper(): start = time.time() f() end = time.time() print('spend %s'%(end-start)) if flag : print('将这个操作时间写入日志') return wrapper return show_time @time_logger(1) def foo(): print('foo..........') time.sleep(2) foo()