python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用
python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。装饰器可能只看表面意思不太好理解,
结合例子可能更好理解一点
import time
def func():
print("hello")
time.sleep(2)
print("world")
if __name__=="__main__":
func
如果需要分析函数性能,统计计算时间,最简单的办法如下:
import time
def func2():
start = time.time()
print("hello")
time.sleep(2)
print("world")
end = time.time()
print("time is {}".format(end-start))
这是最简单的逻辑,直接改没啥问题,如果比较复杂呢,你敢直接改核心逻辑吗,你不怕原来正常的逻辑改出bug吗,怎么办,那就分离呗:
import time
def func():
print("hello")
time.sleep(2)
print("world")
def deco(func):
start = time.time()
func()
end = time.time()
print("time is {}".format(end - start))
if __name__ == '__main__':
#func
deco(func)
但是,这样的做法也有一个问题,就是n多个func,如果都要添加这个功能,就得执行n多deco()函数,是不是显得有些麻烦?
下面做一些改动,来避免计时功能对func函数调用代码的影响:
import time
def deco(func):
def wrapper():
start = time.time()
func()
end = time.time()
print("time is {}".format(end - start))
return wrapper()
@deco
def func():
print("hello")
time.sleep(2)
print("world")
if __name__ == '__main__':
func
现在是不是好了,既不影响原来的业务逻辑,又能拓展我们想要的性能分析。
这里只是最原始的装饰器,如果需要参数,只需要少许修改就可以:
import time
def deco(func):
def wrapper(*args,**kwargs):
start = time.time()
print("args:",args)
print("kwargs:",kwargs)
func(*args,**kwargs)
end = time.time()
print("time is {}".format(end - start))
return wrapper
@deco
def func(*args,**kwargs):
print("hello")
time.sleep(2)
print("world")
if __name__ == '__main__':
func(1,2,a=3,b=4)
看现在是不是越来越强大了,对源代码基本不会有侵入。
你可能会想,能不能支持多个装饰器,当然可以:
import time
def deco(func):
def wrapper(*args,**kwargs):
start = time.time()
print("args:",args)
print("kwargs:",kwargs)
func(*args,**kwargs)
end = time.time()
print("time is {}".format(end - start))
return wrapper
def deco2(func):
def wrapper(*args,**kwargs):
start = time.time()
print("args2:",args)
print("kwargs2:",kwargs)
func(*args,**kwargs)
end = time.time()
print("time2 is {}".format(end - start))
return wrapper
@deco
@deco2
def func(*args, **kwargs):
print("hello")
time.sleep(2)
print("world")
if __name__ == '__main__':
func(1, 2, a=3, b=4)
#执行顺序=deco(deco2(func(1, 2, a=3, b=4)))
而且,装饰器本身也可以支持参数:
def deco(arg=True):
if arg:
def _deco(func):
def wrapper(*args, **kwargs):
start = time.time()
print("args:", args)
print("kwargs:", kwargs)
func(*args, **kwargs)
end = time.time()
print("time is {}".format(end - start))
return wrapper
else:
def _deco(func):
return func
return _deco
@deco(True)
def func(*args, **kwargs):
print("hello")
time.sleep(2)
print("world")
if __name__ == '__main__':
func(1, 2, a=3, b=4)
可以看到,如果装饰器本身需要支持参数,那么装饰器就需要多一层的内嵌函数,这时候func(1,2,a=3,b=4)=deco(True)(func(1,2,a=3,b=4)).
所以有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的,有很多经典使用场景,像插入日志、性能分析、事务处理等等。