考虑如下代码执行顺序:

def decorator_a(func):
    print('Get in decorator_a')
    
    def inner_a(*args, **kwargs):
        print('Get in inner_a')
        return func(*args, **kwargs)
    return inner_a
    
    
def decorator_b(func):
    print('Get in decorator_b')
    
    def inner_b(*args, **kwargs):
        print('Get in inner_b')
        return func(*args, **kwargs)
    return inner_b
    
    
@decorator_a
@decorator_b
def f(x):
    print('Get in f')
    return x * 2
    
    
 f(1)

结果为:

Get in decorator_b
Get in decorator_a
Get in inner_a
Get in inner_b
Get in f

我们知道,用语法糖的装饰器我们可以将被装饰的函数转换为

def f(x):
    print('Get in f')
    return x * 2
f = decorator_a(decorator_b(f))  # decorator 定义省略
    
# 调用 f 函数
f(1)

因此,当执行到 f = decorator_a(decorator_b(f)) 时,先执行了 decorator_b(f) ,输出 Get in decorator_b 并返回 inner_b 函数,然后传递给 decorator_a 作为参数,即 decorator_a(inner_b) ,输出 Get in decorator_a 并返回 inner_a 函数。

当执行到 f(1) 调用 f 函数时,相当于执行了 decorator_a(decorator_b(f))(1) 。由前面得知 decorator_a(decorator_b(f)) 返回了 inner_a 函数,所以 decorator_a(decorator_b(f))(1) 等价于 inner_a(1) ,于是进入到 inner_a 函数输出 Get in inner_a 并执行函数内的 func(*args, **kwargs),这里 func 即为 decorator_a 的参数:decorator_b(f) ,即 func(*args, **kwargs) -> decorator_b(f)(1) -> inner_b(1) ,所以类似于前面同样的逻辑,进入到 inner_b 函数输出 Get in inner_b 并执行 func(*args, **kwargs),这里 func 即为 f 函数,所以最后进入 f 函数,输出 Get in f

前面的逻辑看起来有点绕,我们也可以用栈的思想来理解:在定义装饰器函数的时候,相当于函数入栈,上面的例子就是 f -> decorator_b -> decorator_a;在被调用的地方,相当于函数出栈 decorator_a -> decorator_b -> f

由上面的例子,我们再来思考一下三层嵌套的装饰器(即包含装饰器本身的参数)的输出情况:

def decorator_a(n):
    print(f'Get in decorator_a, n: {n}')
    
    def middle_a(func):
        print('Get in middle_a')
    
        def inner_a(*args, **kwargs):
            print('Get in inner_a')
            return func(*args, **kwargs)
        return inner_a
    return middle_a
    
    
def decorator_b(n):
    print(f'Get in decorator_b, n: {n}')
    
    def middle_b(func):
        print('Get in middle_b')
    
        def inner_b(*args, **kwargs):
            print('Get in inner_b')
            return func(*args, **kwargs)
        return inner_b
    return middle_b
    
    
@decorator_a('a')
@decorator_b('b')
def f(x):
    print('Get in f')
    return x * 2
    
    
f(1)

结果为:

Get in decorator_a, n: a
Get in decorator_b, n: b
Get in middle_b
Get in middle_a
Get in inner_a
Get in inner_b
Get in f

对于三层嵌套结构,我们同样可以将语法糖形式转换为函数形式。上面的例子可以写为:

def f(x):
    print('Get in f')
    return x * 2
f = decorator_a(n)(decorator_b(n)(f))  # decorator 定义省略
    
# 调用 f 函数
f(1)

与两层嵌套不同的是,三层嵌套在包装时已经调用了最外层,并返回内层函数(先剥开了最外层,并返回剩下的内容,剩下的内容不难发现与二层装饰器相同)。如果我们只看一个装饰器的话,即 f = decorator_a(n)(f) 所以会先调用装饰器,进入装饰器最外层并输出 Get in decorator_a, n: a ,然后返回里面两层结构(后面的分析就与前一个例一样了)