语法
@文件名
def show(fn):def temp(x,y):print("===========")z = fn(x,y)return zreturn tempdef myadd(a,b):return a+bdef mysubstract(a,b):return a-bdef mymulitply(a,b):return a*bdef mydivide(a,b):return a/badd = show(myadd)print(add(3,4))substract = show(mysubstract)print(substract(10,3))
优化使用@show 等价于 函数实际名=修饰器函数名(函数实际名)
def show(fn):def temp(x,y):print("===========")return fn(x,y)return temp@show #myadd = show(myadd)def myadd(a,b):return a+b@showdef mysubstract(a,b):return a-b@showdef mymulitply(a,b):return a*b@showdef mydivide(a,b):return a/b
改进能适应不同格式的参数
在执行功能函数前把通用的功能或者要对函数参数进行的处理放到装饰器中去进行,常见的例如输出logging
def funx(*args,**kwargs): #args 收集关键字 #kwargs 收集关键字参数(字典等)print(args,kwargs)print(funx(1)) >>(1,)print(funx(6,4,6,刘能=183283231123)) >>(6,4,6) {"刘能":"183283231123"}def decorator(function):def wrapper(*args,**kwargs):print("=====开始======")print(list(args)[0]) #元组转化为列表进行处理x=function(*args,**kwargs)return xreturn wrapper@decoratordef myadd(a,b,c):return a+b+c@decoratordef mysubstract(a,b,c):return a-b-c@decoratordef mymulitply(a,b):return a*b@decoratordef mydivide(a,b):return a/bprint(myadd(3,4,3))print(mysubstract(10,6,2))print(mymulitply(10,6))print(mydivide(10,2))
装饰器会修改原方法的name和doc,理论上我们不允许修改它,可以通过functools的wraps来实现
from functools import wrapsdef log(flag):def decorate(func):@wraps(func)def _wrap(*args,**kwargs):try:if flag:func(*args,**kwargs)print('name ',func.__name__)except Exception as e:print(e.args)return _wrapreturn decorate@log(True)def sum(a,b,c):return a+b+cx = sum(1,2,3)print(sum) #打印sum的内存地址print(sum.__name__) #打印sum的函数名print(x)
有参装饰器
如何传入一个参数到装饰器中,装饰器中不允许直接传参数进入,所以我们一般采用的方法是在无参装饰器外在包裹一层函数,把参数传进去
from functools import wrapsdef get_param(x):def decorate(func):@wraps(func)def wrapper(*args,**kwargs):if x =="a":print('111111')elif x = 'b':print('222222222')res = func(*args,**kwargs)print('the func end')return resreturn wrappersreturn decorate@get_param('a') #decorate = get_param('a') @decoratedef func():print('3333333333333')>>>>print('11111111')print('3333333333')print('the func end')
多个装饰器执行顺序
如果一个函数上有多个装饰器,其执行顺序是按照自下而上的顺序执行的,也就是最里面的先执行,再依次往上去执行,其内存调用类似于堆栈,先进后出,举例如下
def out1(function1):def wrapper1(*args,**kwargs):print("=====wrapper1 开始======")x=function1(*args,**kwargs)print("=====wrapper1 结束======")return xreturn wrapper1def out2(function2):def wrapper2(*args,**kwargs):print("=====wrapper2 开始======")x=function(*args,**kwargs)print("=====wrapper2 结束======")return xreturn wrapper2def out3(function3):def wrapper3(*args,**kwargs):print("=====wrapper3 开始======")x=function3(*args,**kwargs)print("=====wrapper3 结束======")return xreturn wrapper3@out3 # func = out3(out2.wrapper2) return func = out3.wrapper3@out2 # func = out2(out1.wrapper1) return func = out2.wrapper2@out1 # func = out1(func) return func = out1.wrapper1def func():print('111111111')func()>>>>#可以看到func被传递给了out3,即最后home指向了out3.wrapper3#调用out3.wrapper3的function其实是out2.wrapper2#调用out2.wrapper2的function其实是out1.wrapper1print("=====wrapper3 开始======")print("=====wrapper2 开始======")print("=====wrapper1 开始======")print('11111111111')print("=====wrapper1 结束======")print("=====wrapper2 结束======")print("=====wrapper3 结束======")
