装饰器得加使用原则
装饰器叠加使用,按照先里后外,先下后上的原则进行装饰。
让我们从实例中来分析
例两个装饰器out和logger
import datetime
from inspect import signature
from functools import wraps
#测试运行时长
def out(fn1):
def inner(*args,**kwargs):#inner('7',8)
start = datetime.datetime.now()
ret = fn1(*args,**kwargs)#此处fn1('7',8) 为add最初代表的函数体
delt = (datetime.datetime.now() -start).total_seconds()
return ret
return inner
#判断参数类型
def logger(fn):
def wra(*args,**kwargs):#add('7',8) = wra('7',8)
di={}
param = signature(fn).parameters#此处fn为inner。
di.update(zip(param.keys(),args),**kwargs)
di.update(((k,v.default) for k in param.keys()-di.keys()))
for k,v in di.items():
if param[k].annotation != inspect._empty and not isinstance(v,param[k].annotation):
print( "ErrorType")
ret = fn(*args,**kwargs)#此处fn为inner。fn('7',8) = inner('7',8)
return ret
return wra
@out #add = wra = out(wra) = inner
@logger #add = logger(add) = wra
def add(x:str,y:int):
return x+str(y)
按装饰原则
在装饰过程中,第一次logger先装饰,add = logger(add) = wra,logger中的fn为add最初代表的那个函数体
第二次out装饰,add = wra = out(wra) = inner ,out中的fn1位wra函数。所以最后调用add就相当于调用wra。
调用add函数—add(‘7’,8)的执行过程:
add(‘7’,8) = inner(‘7’,8)
执行inner函数:
def out(fn1):
def inner(*args,**kwargs):#iadd('7',8) = inner('7',8)
start = datetime.datetime.now()
ret = fn1(*args,**kwargs)#此处fn1('7',8) = wra('7',8)
delt = (datetime.datetime.now() -start).total_seconds()
return ret
return inner
运行到
ret = fn1(*args,**kwargs)#此处fn1('7',8) = wra('7',8)
执行wra函数
def wra(*args,**kwargs):#wra('7',8)
di={}
param = signature(fn).parameters#此处fn为add最初所表示的那个函数体
di.update(zip(param.keys(),args),**kwargs)
di.update(((k,v.default) for k in param.keys()-di.keys()))
for k,v in di.items():
if param[k].annotation != inspect._empty and not isinstance(v,param[k].annotation):
print( "ErrorType")
ret = fn(*args,**kwargs)#此处fn为add最初所表示的那个函数体
return ret
运行到
ret = fn(*args,**kwargs)#此处fn为add最初所表示的那个函数体
执行add最初表示的函数体
def add(x:str,y:int):
return x+str(y)
然后 ret 接住add函数的返回值,wra函数返回ret, 因为wra = fn1,所以 ret 被inner函数里的ret接住,最后inner函数返回ret,函数调用结束。