• 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

  • 相关阅读:
    认识一下JavaScript
    JAVA并发容器之CopyOnWrite容器
    JAVA并发容器之ConcurrentHashMap
    由浅入深理解java集合(一)——集合框架 Collection、Map
    强引用、软引用、弱引用、虚引用
    Lock和synchronized的选择
    Java并发编程:volatile关键字解析
    java线程并发-Thread类的使用
    SQL语句中:UNION与UNION ALL的区别
    抽象类与接口
  • 原文地址:https://www.cnblogs.com/jiangxiaobo/p/12449126.html
Copyright © 2020-2023  润新知