1.

import time, datetime


class Ly:
    def __init__(self, fun):
        self.fun = fun
        print('this is the first step on ' + str(datetime.datetime.now()))
        time.sleep(1)
        self.fun()

    def __call__(self):
        print('this is the thirty step on ' + str(datetime.datetime.now()))
        time.sleep(1)

@Ly
def show():
    print('this is the second step on ' + str(datetime.datetime.now()))
    time.sleep(1)

if __name__ == "__main__":
    show()
    print('this is the fourth step on ' + str(datetime.datetime.now()))

Python 类装饰器
    





            
python多个装饰器的执行顺序

 

 

2.

import time


class Ly(object):

    def __init__(self, fun):
        print("this is the first step")
        time.sleep(1)
        self.fun = fun

    def __call__(self, *args):
        print("this is the second step")
        time.sleep(1)
        self.fun(*args)
        print("this is the fourth step")
        time.sleep(1)

@Ly
def show(a1, a2, a3, a4):
    print('this is the thirty step', a1, a2, a3, a4)
    time.sleep(1)


show("parm", "1", "1", "1")
print("After first part call")
time.sleep(1)
show("parm", "2", "2", "2")
print("After second part call")

Python 类装饰器
    





            
python多个装饰器的执行顺序

 

从中可以发现:

(1).只要有被类装饰器装饰的对象,类装饰器的 __init__ 函数就会执行(不需要调用)

(2).被类装饰器装饰的函数不论被调用几次,__init__ 函数只会执行一次,并且它的执行是被装饰函数声明装饰时就自动执行,不需要手动调用

(3).当被装饰函数存在参数时,从 __call__ 函数传进参数(不必须 *args,但这是一种规范 def __call__(self,*args,**kwargs))

     *args是指字符串,**kwargs是指字典

3.

import time

class Ly:
    def __init__(self, one_parm, two_parm, three_parm):
        self.one_parm = one_parm
        self.two_parm = two_parm
        self.three_parm = three_parm

    def __call__(self, fun):
        print('性别为' + self.one_parm + "" + self.two_parm + "岁的" + self.three_parm)
        time.sleep(1)
        def info(*args):
            fun(*args)

        return info


@Ly("", "22", "ly")
def show(name, age, sex):
    print('性别为' + sex + "" + age + "岁的" + name)


show("蓝月", "20", "")

Python 类装饰器
    





            
python多个装饰器的执行顺序

 

 

注意:

(1).装饰器有装饰器的参数,函数(被装饰器修饰的函数)有函数的参数,不可混淆

(2).装饰器函数的参数从 __init__ 函数中传,函数的参数从 __call__ 函数中传

 

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_b
@decorator_a
def f(x):
    print 'Get in f'
    return x * 2
  
f(1)

执行如上所示代码,最后的执行结果为:

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

我们来分析下,为什么会是这样的顺序(验证的过程中可以通过打断点的方式来观察函数的程序的执行流程)。

首先:

1、装饰器函数在被装饰函数定义好后立即执行。

我们把代码最后一行注掉:

# f(1)
重新执行,会发现最后执行结果为:

Get in decorator_a
Get in decorator_b
 

说明装饰器函数在被装饰函数定义好后就立即执行。而且执行顺序是由下到上开始装饰。调用decorator_a时,f被装饰成inner_a,调用decorator_b时,f被装饰成inner_b。

通过在最后执行:print(f), 执行结果为<function inner_b at 0x00000000038F15F8>可验证。

所以如上所示代码中,最后执行f(1)时,f已经变成了inner_b,而inner_b中return的func,实则为inner_a, inner_a中return的func才是最终的f。

所以最后的调用顺序为

inner_b --->inner_a--->f

执行结果为:

Get in inner_b
Get in inner_a
Get in f

 

在实际应用的场景中,当我们采用上面的方式写了两个装饰方法比如先验证有没有登录 @login_required , 再验证权限够不够时 @permision_allowed 时,我们采用下面的顺序来装饰函数:

@login_required
@permision_allowed
def f()
  # Do something
  return

总结一下:

多个装饰器装饰函数时,有个规律是从小到上包裹(装饰)函数,从上到下执行。


原文:https://blog.csdn.net/qq_35462323/article/details/90633796

相关文章: