装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
在编程过程中我们会调用许多函数,例如:
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()