python装饰器
不修改原有的函数的基础上,要给函数添加功能。
比如:
- 引入日志功能
- 函数执行时间的统计
- 执行函数前预备的处理
- 执行函数后的清理工作
- 等
如果直接在原来的函数上添加可能会破坏原有的函数。(违背开放封闭原则)
- 封闭:实现的功能代码块
- 开放:拓展开发
如果再将这个函数重新写一版本,如果只是一层调用还好。如果是频繁的调用,并且有可能需要添加的功能是分离的,然后写多层嵌套函数。这样的话我们的代码量将会增加,并且存在很多冗余现象。
装饰器目的:在不修改原码的情况下进行功能的拓展。
那么我们怎么办呢?装饰器就是解决这样的问题的。
# 定义一个装饰器
def decorator(func):
print('-----------1-----------')
def wrapper():
func()
print("刷漆")
print("铺地板")
print("买家具")
print("精修")
print('-----------2-----------')
# 这里不能返回函数,必须是函数名
return wrapper
# 装饰器的使用
@decorator
def house():
print("现在是毛坯房")
if __name__ == '__main__':
house()
观察上面的代码在调用house()的时候先找到def house()
这句话,然后因为他被decorator(func)
修饰过。所以先打印decorator中内容,然后将函数内容进行修饰,就是def wrapper()
函数的部分,将这个修饰完之后,返回值是wrapper
,将这个现在修饰结束之后的这个函数传给house。相当于@decorator
就是执行了一下house=decorater(house)
。这就是修饰的过程。
从内存的角度看:先调用函数house,但是因为他有修饰器,然后house本来是一个函数地址A然后,将这个地址A传给修饰器函数,在修饰器函数中将原来的函数功能进行添加得到新的函数wrapper
然后修饰器函数将修饰完之后的函数的地址B返回传给house。调用的是house实际执行的是wrapper。 换句话说就是,此house非原本的house了。
问:在上面的实例中func是没有参数的,如果有参数怎么办呢?
答:在wrapper中调用的
func()
中加入参数即可。问:修饰各种各样的函数怎么办?
答:
func(*args,**kwargs)
装饰器函数看起来就像闭包,但是实际上还是有区别的。
装饰器函数的参数是函数名,闭包的参数是没有限制的。
万能模板:
# 定义一个装饰器
def decorator(func):
# 打印提示信息
def wrapper(*args, **kwargs):
# 执行前的预备工作
# -------
# 添加的功能在预备工作和清除工作中间进行操作
func(*args, **kwargs)
# 执行后的清除工作
# -------
return args# 被修饰后的返回值
return wrapper
# 装饰器的使用
@decorator
def func(*args, **kwargs):
# 要被修饰的函数。
pass
if __name__ == '__main__':
args = func(1, 2, 3)
print(*args)
使用实例
import time
# 装饰器01
def deco01(func):
def wrapper(*args, **kwargs):
print("this is deco01")
startTime = time.time()
func(*args, **kwargs)
endTime = time.time()
msecs = (endTime - startTime) * 1000
print("time is %d ms" % msecs)
print("deco01 end here")
return wrapper
# 装饰器02
def deco02(func):
def wrapper(*args, **kwargs):
print("this is deco02")
func(*args, **kwargs)
print("deco02 end here")
return wrapper
@deco01
@deco02
def func(a, b):
print("hello,here is a func for add :")
time.sleep(1)
print("result is %d" % (a + b))
if __name__ == '__main__':
f = func
f(3, 4)