Python 类装饰器

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()))

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")

从中可以发现:

(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", "")

注意:

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

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

python多个装饰器的执行顺序

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

原文地址:https://www.cnblogs.com/jiangxiaobo/p/12449126.html