在解读之前需要先做一个实验:
def mess1(f1):
print('before 1')
def run1(*args,**kwargs):
print('start process1 {}'.format(f1.__name__))
res=f1(*args,**kwargs)
print('end process1 {}'.format(f1.__name__))
return res
return run1
def mess2(f2):
print('before 2')
def run2(*args,**kwargs):
print('start process2 {}'.format(f2.__name__))
res=f2(*args,**kwargs)
print('end process2 {}'.format(f2.__name__))
return res
return run2
@mess1
@mess2
def A(x1,x2):
print('laowang')
return x1+x2
print(A(1,2))
运行的结果如下:
before 2
before 1
start process1 run2
start process2 A
laowang
end process2 A
end process1 run2
3
似乎和想象中执行的顺序不太一样,我们接下来进行分析:
首先需要有一些概念,这里我按照自己的理解将装饰器分为两个阶段:
(1)初始化装饰器阶段(构建装饰器)
(2)装饰器执行阶段
在解读装饰器的执行顺序我们需要知道真正的f=mess1(mess2(f2))=初始化+run1(run2(*args,**kwargs))=初始化+f1(f2(*args,**kwargs))
在初始化装饰器的阶段,也就是构造f=mess1(mess2(f2))
,此刻还涉及不到执行阶段,但是接下来就需要进行初始化,就会执行
print('before 2')
和print('before 1')
,之所以在先执行mess22而不是mess1,是因为构造的时候根据就近原则,
找到@mess2,使用一个不恰当的比如就好比,穿衣服先穿里面的;
经历过初始化阶段之后,我们就直接执行run1(run2(*args,**kwargs))
,我们可以看到首先将run2只是run1的一个参数,也就是在run1的f实际在执行的时候回换成run2;
真到真正执行的时候,相当于是run1调用run2,所以run1肯定先执行,因此在run1中执行到res=f1(*args,**kwargs)
的时候就会直接跳转到res=f2(*args,**kwargs)
,
当res=f2(*args,**kwargs)
,执行f2的时候就会调用A(),执行完成后,就会执行print('end process2 {}'.format(f2.__name__))
,
接下来return的值直接赋值给run1里面的res=f1(*args,**kwargs)
,然后顺理成章的执行print('end process1 {}'.format(f1.__name__))
。
至此,过程分析完成