zoukankan      html  css  js  c++  java
  • 装饰器拓展

    一:装饰器的缺点,解决方法

    正常的函数,可以使用内置方法打印函数名,注释等方便开发。

    def f(*args, **kwargs):
        """
        这是一个测试装饰器的函数,没什么其他的用法
        :param args:
        :param kwargs:
        :return:
        """
        print("2018-06-04")
    
    print(f.__name__)
    print(f.__doc__)
    
    # f
    
    # 这是一个测试装饰器的函数,没什么其他的用法
    # :param args:
    # :param kwargs:
    # :return:

    在加上装饰器之后,使用内置方法打印函数名,变成了inner,注释成了None

    def wrapper(func):
        def inner(*args, **kwargs):
            print("start")
            ret = func(*args, **kwargs)
            print("end")
            return ret
        return inner
    
    @wrapper
    def f(*args, **kwargs):
        """
        这是一个测试装饰器的函数,没什么其他的用法
        :param args:
        :param kwargs:
        :return:
        """
        print("hello world")
    
    print(f.__name__)
    print(f.__doc__)
    
    # inner
    # None
    View Code

    出现上面的情况的原因是因为函数经过装饰之后,实际上都是在执行inner函数。

    为了避免这种情况,可以引入一个模块来解决这个问题

    from functools import wraps
    
    
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            print("start")
            ret = func(*args, **kwargs)
            print("end")
            return ret
    
        return inner
    
    
    @wrapper
    def f(*args, **kwargs):
        """
        这是一个测试装饰器的函数,没什么其他的用法
        :param args:
        :param kwargs:
        :return:
        """
        print("hello world")
    
    
    print(f.__name__)
    print(f.__doc__)
    
    # f
    # 
    # 这是一个测试装饰器的函数,没什么其他的用法
    # :param args:
    # :param kwargs:
    # :return:
    View Code

    二:多个装饰器的执行顺序

    大多的认知仅是:多个装饰器的执行顺序从上到下,现在,通过一个例子来深入的分析一下装饰器装饰的函数的整个运行过程。

    def wrapper_a(func):          #执行结果:返回一个函数a
    print(func.__name__+'_wrapper_a')
    print('*' * 20)
    def a(*args, **kwargs):
    print('get inner a')
    func(*args, **kwargs)
    return a

    def wrapper_b(func): #执行结果:返回一个函数b
    print(func.__name__+'_wrapper_b')
    print('*'*20)
    def b(*args, **kwargs):
    print('get inner b')
    func(*args, **kwargs)
    return b

    @wrapper_a
    @wrapper_b
    def f():
    print("hello world")

    f()
    # f_wrapper_b
    # ********************
    # b_wrapper_a
    # ********************
    # get inner a
    # get inner b
    # hello world

    在被装饰函数f加括号调用时,函数f作为参数,被传入就近的装饰器wrapper_b中,然后装饰器wrapper_b开始执行。

    #执行结果有三:
    1:执行:print(func.__name__+'_wrapper_b')和print('*'*20)
        f_wrapper_b
        ********************
    2:执行:def b(*args, **kwargs):
           .........
           .........
      定义了一个闭包函数a,此时:func
    = f, 3:执行:return b 把以func= f 包裹的闭包函数b作为返回值返回给调用者。 注意:此时函数b是定义阶段,不会执行函数体代码。

    在得到返回值后,返回值作为一个参数,被传入装饰器wrapper_a中,然后装饰器wrapper_a开始执行。

    注意:此时的返回值是一个闭包函数b,其代码如下:

    func = f
    def b(*args, **kwargs):
        print('get inner b')
        func(*args, **kwargs)

    wrapper_a执行的结果如下:

    执行结果有三:
    1:执行:print(func.__name__+'_wrapper_a')和print('*'*20)
        b_wrapper_a
        ********************
    2:执行:
    def a(*args, **kwargs):
        print('get inner a')
        func(*args, **kwargs)
      定义了一个闭包函数a,此时:func = b,
    3:执行:return a
        把以func= b 包裹的闭包函数a作为返回值返回给调用者。
        注意:此时函数a是定义阶段,不会执行函数体代码。

    此时的返回值同样是一个闭包函数a,其代码如下:

    func = b
    def a(*args, **kwargs):
        print('get inner a')
        func(*args, **kwargs)

    综上所述:在被装饰函数f加括号调用后,代码运转得到一个返回值,并把这个返回值赋值给变量f,这样就得到了以下的代码:

    #函数f
    func = b
    def a(*args, **kwargs):
        print('get inner a')
        func(*args, **kwargs)

    而闭包函数b就是装饰器wrapper_b运行完成的结果

    变量f是一个函数,加括号调用,就开始执行代码:

    print('get inner a')  #结果:get inner a
    func(*args, **kwargs) # func = b,实际执行b(*args, **kwargs)

    闭包函数b执行代码:

    print('get inner b') #结果:get inner b
    func(*args, **kwargs) # func = f,实际执行f(*args, **kwargs)

    最后执行被装饰的函数f:

    print("hello world") #结果:hello world

    因此多个装饰器的执行效果在展现上是从上到下的顺序:

    # get inner a
    # get inner b
    # hello world

    但是现在已经可以知道,这只是一种假象,实际的执行来说,是从最近的装饰器开始执行:

    # f_wrapper_b
    # ********************
    # b_wrapper_a
    # ********************

    上面的执行结果很好的解释了这一点。

    因此可以说:

    装饰器从执行效果来说是:从上到下;

    从实际的执行来说:是从最近的装饰器开始。

  • 相关阅读:
    泛型应用----泛型接口、泛型方法、泛型数组、泛型嵌套
    有选择性的启用SAP UI5调试版本的源代码
    SAP UI5应用入口App.controller.js是如何被UI5框架加载的?
    SAP WebIDE里UI5应用的隐藏文件project.json
    SAP UI5的support Assistant
    如何用SAP WebIDE的Fiori创建向导基于ABAP OData service快速创建UI5应用
    SAP Cloud Platform上Destination属性为odata_gen的具体用途
    Marketing Cloud contact主数据的csv导入
    Marketing Cloud的contact merge机制
    如何让某些用户对Marketing Cloud的contact数据只能实施只读操作
  • 原文地址:https://www.cnblogs.com/li1992/p/9135765.html
Copyright © 2011-2022 走看看