python笔记——多个decorator的执行顺序

事实上,用这样一段代码就能看出执行顺序:

def decorator_a(func):
    print('decorator a running.')

    def deco_a(*args, **kwargs):
        print('pretreatment a')
        res = func(*args, **kwargs)
        print('post processing a')
        return res

    print('decorator a finished.')
    return deco_a


def decorator_b(func):
    print('decorator b running.')

    def deco_a(*args, **kwargs):
        print('pretreatment b')
        res = func(*args, **kwargs)
        print('post processing b')
        return res

    print('decorator b finished.')
    return deco_a


@decorator_a
@decorator_b
def f(x):
    print('running f.')
    return x*2


print('')


def g(x):
    print('running g.')
    return x*3


g = decorator_a(g)
g = decorator_b(g)


print('')
print('\n', f(1), '\n')
print('\n', g(1), '\n')

 输出:

decorator b running.
decorator b finished.
decorator a running.
decorator a finished.

decorator a running.
decorator a finished.
decorator b running.
decorator b finished.

pretreatment a
pretreatment b
running f
post processing b
post processing a

 2 

pretreatment b
pretreatment a
get in g
post processing a
post processing b

 3 

首先,嵌套函数的外层内容在函数定义并装饰的过程中就已经被执行了。其次,装饰器的装饰顺序是靠近函数的装饰器先进行装饰,远离函数定义位置的装饰器后进行装饰。装饰函数内定义的函数定义之前的代码会在装饰过程中执行,而内层函数则会被返回给原函数。换而言之,在第一次装饰(@decorator_b)后,f已经变成了deco_b。而在第二次装饰时,相当于deco_b被传入decorator_a。装饰过程等于下列装饰函数调用

def i(x):
    return x*2


i = decorator_a(decorator_b(i))
print('')
print(i(1))

上述例子中,显示的,装饰过程也可以等价于下列过程:

print('decorator b running.')
print('decorator b finished.')
print('decorator a running.')
print('decorator a finished.')


def h(x):
    print('pretreatment a')
    print('pretreatment b')
    print('running h.')
    res = x*2
    print('post processing b')
    print('post processing a')
    return res


print(h(1), '\n')

而调用函数进行装饰则正好相反,调用过程是自上往下的,调用过程必须写在函数下方。

<think>嗯,用户问的是多个Python装饰器的执行顺序,这个问题我之前学过,但可能得仔细回忆一下才能确保正确。首先,装饰器是Python中的一个重要特性,允许在不修改原函数代码的情况下增加功能。当多个装饰器叠加使用时,它们的执行顺序可能会让人有点困惑,我得理清楚这个顺序到底是怎样的。 我记得装饰器的语法是通过@符号放在函数定义之前,而装饰器本身是一个高阶函数,接受一个函数作为参数并返回一个新的函数。当多个装饰器堆叠在一起时,它们是从下往上还是从上往下执行的呢?比如,如果有@decorator1和@decorator2,哪个先执行? 这时候,可能需要用一个例子来验证。假设有两个装饰器,dec1和dec2,应用在函数f上: @dec1 @dec2 def f(): pass 这种情况下,实际的效果应该是dec2先被应用,然后是dec1。也就是说,装饰器的顺序是从下往上的。但这里可能涉及到装饰器本身的实现方式。比如,每个装饰器返回一个包装函数,那么当装饰器被嵌套应用时,内部的装饰器先处理原函数,外层装饰器再处理内部装饰器返回的结果。 不过,可能更准确的说法是,装饰器的执行顺序是按照靠近函数定义的装饰器先执行,然后依次向外。也就是上面的例子中,dec2先执行,将函数f传递给dec2,返回的装饰后的函数再传递给dec1进行装饰。所以最终的调用顺序是dec2的装饰逻辑先执行,然后是dec1的。但在实际调用被装饰的函数时,外层装饰器的逻辑会先被触发,因为内层的装饰器已经被包裹在外层之中了。 例如,如果dec1和dec2都打印一些信息,可能在装饰的时候,dec2先被调用,然后dec1。而在调用函数f时,会先执行dec1的包装函数,然后调用dec2的包装函数,最后执行原函数f。所以执行顺序是装饰器从上到下应用,但调用时的顺序是外层到内层,类似于洋葱的层次结构。 但可能用户更关心的是装饰器应用时的顺序和调用时的执行顺序的区别。比如,装饰器本身的代码(比如在装饰时执行的代码)是按顺序从上到下,还是从下到上?比如,装饰器函数在被应用时的执行顺序。 例如,假设装饰器函数是这样的: def dec1(func): print("dec1 applied") def wrapper(): print("dec1 wrapper") func() return wrapper def dec2(func): print("dec2 applied") def wrapper(): print("dec2 wrapper") func() return wrapper 当应用这两个装饰器时: @dec1 @dec2 def f(): print("f") 这时候,装饰器在装饰阶段(也就是导入模块时)的执行顺序是怎样的?应该是先应用@dec2,再应用@dec1,所以输出会是"dec2 applied"然后"dec1 applied"。这说明装饰器的应用顺序是从下往上的,也就是靠近函数的先执行。 而当调用f()时,执行顺序会是先执行dec1的wrapper,再执行dec2的wrapper,最后执行原函数f。因为dec1包装了dec2返回的wrapper,所以调用f()实际上是调用dec1的wrapper,其中会调用dec2的wrapper,再调用原函数。 所以总结起来,多个装饰器的应用顺序是从下往上,但执行时的顺序是从外到内,也就是先应用外层装饰器的逻辑,再进入内层装饰器,最后执行原函数。 为了确保正确,可能需要编写一个具体的例子来测试。比如,用两个装饰器分别打印信息,看看它们的执行顺序是否符合预期。这有助于验证之前的理解是否正确。 另外,可能需要注意,装饰器本身的实现方式会影响执行顺序。比如,如果装饰器返回的是原函数,或者没有正确的嵌套结构,可能会有不同的结果。但在通常情况下,正确的装饰器实现应该按照上述的顺序执行。 总之,多个装饰器的执行顺序是:装饰器按照从下往上的顺序应用,而调用被装饰的函数时,执行顺序是外层装饰器的逻辑先执行,然后依次向内,最后执行原函数。</think>多个Python装饰器的执行顺序遵循**由近到远装饰,由外到内执行**的规则。具体分为两个阶段: --- ### 一、装饰阶段(加载时执行) 装饰器的应用顺序是**从下往上**(靠近函数的先应用): ```python @decorator1 # 后应用:外层包装 @decorator2 # 先应用:内层包装 def my_func(): pass ``` 等价于: ```python my_func = decorator1(decorator2(my_func)) ``` --- ### 二、执行阶段(调用时执行) 函数调用时,装饰器的执行顺序是**从外到内**(外层的装饰器逻辑先触发): ```python def decorator1(func): def wrapper(): print("Decorator1逻辑开始") # 先执行 func() print("Decorator1逻辑结束") # 后执行 return wrapper def decorator2(func): def wrapper(): print("Decorator2逻辑开始") # 其次执行 func() print("Decorator2逻辑结束") # 其次结束 return wrapper @decorator1 @decorator2 def my_func(): print("原函数逻辑") # 最后执行 ``` 调用`my_func()`时输出: ``` Decorator1逻辑开始 Decorator2逻辑开始 原函数逻辑 Decorator2逻辑结束 Decorator1逻辑结束 ``` --- ### 三、类比洋葱模型 装饰器的嵌套行为类似洋葱: $$ \text{Decorator1} \rightarrow \text{Decorator2} \rightarrow \text{原函数} \rightarrow \text{Decorator2结束} \rightarrow \text{Decorator1结束} $$ --- ### 四、验证示例 编写一个简单的测试代码: ```python def deco1(func): print("应用deco1") def wrapper(): print("执行deco1") func() return wrapper def deco2(func): print("应用deco2") def wrapper(): print("执行deco2") func() return wrapper @deco1 @deco2 def test(): print("执行test") test() ``` 输出结果: ``` 应用deco2 应用deco1 执行deco1 执行deco2 执行test ``` --- ### 五、关键结论 1. **装饰顺序**:从下往上(`@deco2`先应用,`@deco1`后应用)。 2. **执行顺序**:从上往下(外层`deco1`的逻辑先触发,内层`deco2`的逻辑后触发)。 3. **本质原因**:装饰器是函数嵌套的语法糖,外层装饰器包裹内层装饰器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值