多个装饰器的执行顺序
在上一篇的博客中已经说明了装饰器自身的执行时机是在python解释器第一次读到@符号的时候执行的,这个根据现象是可以推测出来的,再结合装饰器的本质以及闭包也能够完全地理解这个知识点。那么当多个装饰器修饰一个函数时,执行顺序又是怎样的呢?看下面的代码
#coding=utf-8
def f1(func):
print('in f1')
def f1_inner():
print('in f1_inner')
func()
return f1_inner
def f2(func):
print('in f2')
def f2_inner():
print('in f2_inner')
func()
return f2_inner
@f1
@f2
def f():
print('in f')
if __name__ == '__main__':
pass
#f()
结果:
in f2
in f1
在上面的这个例子中装饰器f1和f2都是用来修饰函数f的,且顺序时f1在前f2在后。没有调用函数f,得到的打印结果如上。原因是:装饰器是用来修饰函数的,当python解释器读到@f1时发现下面的不是函数,而是另一个装饰器f2,因此才优先执行了f2,当f2执行完后,f2返回的才是一个函数的引用,因此才返回来执行f1。因此得出结论:装饰器本身的执行顺序和修饰顺序相反。
那么加上函数调用后结果又是怎样的呢?
#coding=utf-8
def f1(func):
print('in f1')
def f1_inner():
print('in f1_inner')
func()
return f1_inner
def f2(func):
print('in f2')
def f2_inner():
print('in f2_inner')
func()
return f2_inner
@f1
@f2
def f():
print('in f')
if __name__ == '__main__':
#pass
f()
结果:
in f2
in f1
in f1_inner
in f2_inner
in f
分析一下为什么是这个结果:如果上面的例子没问题的话,前两行的结果是毋庸置疑的。然后我们把装饰器哪里那里的三行代码加个注释,如下:
@f1 #f = f1(f)
@f2 #f = f2(f)
def f():
print('in f')
这个换成闭包的 调用语句,因为装饰器f2比f1更近修饰函数f,因此函数f第一次返回的是f2中f2_inner的引用,然后才是f1中f1_inner函数的引用,最后才是函数f本身。由此得出:在多个装饰器修饰一个函数时,执行顺序是由内层装饰器向外侧开始的,最后才是被修饰的函数,