Python多个装饰器的执行顺序

看了好多相关文章,也有些有错误,还是自己记录一下吧.

def decrator_a(func):
    print("enter decrator_a")
    def inner_a(*args,**kwargs):
        print("enter inner_a")
        ret = func(*args,**kwargs)
        print("leaving  inner_a")
        return ret
    print("leaving decrator_a")
    return inner_a
    
	
def decrator_b(func):
    print("enter decrator_b")
    def inner_b(*args,**kwargs):
        print("enter inner_b")
        ret = func(*args,**kwargs)
        print("leaving  inner_b")
        return ret
    print("leaving decrator_b")
    return inner_b
    
	
@decrator_a
@decrator_b 
def f(*args,**kwargs):
	print("==f==")
#相当于decrator_a(decrator_b(f))
f()

执行结果为:

>>> 
RESTART: C:/Users/Administrator/AppData/Local/Programs/Python/Python36/tests/decrator_test.py 
enter decrator_b
leaving decrator_b
enter decrator_a
leaving decrator_a
enter inner_a
enter inner_b
==f==
leaving  inner_b
leaving  inner_a

解释一下顺序
明确两点 一是装饰器的执行顺序从下往上,函数调用时从上往下. 二是装饰器函数在被装饰函数定义好后立即执行
一好理解,二的意思就是说即使f没有执行,上面的装饰器函数还是会执行(可以把f()删掉直接运行一下试试)

首先例子中的装饰器顺序相当于decrator_a(decrator_b(f)), 而decrator_b(f)返回的就是一个函数,如此循环的话,在多个装饰器也可以看成只有最外层的一个.另外函数f经过装饰器装饰后,函数f = decrator_a(decrator_b(f)),
然后根据装饰器的特点,执行顺序从近到远,或者说由下而上,先执行decrator_b(f),看代码,先打印一个①"enter decrator_b",然后定义了一个函数inner_b, 返回值为f的执行结果,然而,这个inner_b这个函数并没有被调用,所以相当于一个pass,可以暂时跳过,然后打印一个②"leving decrator_b", 并返回一个函数inner_b,这时候返回这个函数,返回的是函数,而不是函数的执行结果,所以此时inner_b函数还是没有执行,只是 被返回了
这时就变成了decrator_a(inner_b),跟据代码,也是先打印③"enter decrator_a", 然后也是定义一个函数inner_a,同样当成是pass,然后打印④"leaving decrator_a", 然后返回inner_a,
如果没有f()这行,会返回这个结果,会打印四行,分别是
enter decrator_b
leaving decrator_b
enter decrator_a
leaving decrator_a
加上f()这行之后,就开始执行函数了
因为此时函数f是经过装饰器装饰过的了, f = inner_a, f() = inner_a()
然后再来看函数inner_a, 相当于

def inner_a(*args,**kwargs):
	print("enter inner_a")
	ret = inner_b(*args,**kwargs)
	print("enter inner_a")
	return ret

所以这时候打印一个"enter inner_a", 然后执行inner_b并把结果赋值给变量ret, inner_b执行时打印一句"enter inner_b", 然后开始执行函数f,这个函数f是还没有经过装饰器装饰的函数,(相当于 a = 1 a = a +1 ,a = a +1 中等号后面的a还是原来的a=1),所以应该打印一行⑤" =f=", 这时函数f执行完了,返回上一级的inner_b中,继续执行,打印一行⑥"leaving inner_b", 然后返回inner_b中的ret,因为函数f没有返回值,所以返回None, 再往上一级返回inner_a中,ret = None,打印一行⑦"leaving inner_a",最后返回ret,也就是None, 这里并没有打印返回结果,所以None不会在打印结果中出现.

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值