一篇文章完全搞定python装饰器执行顺序

150 阅读2分钟

在解读之前需要先做一个实验:

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__))。 至此,过程分析完成