• [TimLinux] Python 装饰器


    1. 装饰器

    1. 一种语法格式,用于替换另外一个编码风格,一种语法糖,通过语法结构明确标识出这样一种语法。
    2. 自动在被装饰对象尾部执行代码(不使用装饰器语法时,需要明确写明的代码)
    3. 被装饰对象可以为函数、类,被装饰对象为函数(则定义装饰器为函数装饰器),被装饰对象为类(则定义装饰器为类装饰器)
    4. 装饰器自身可以是函数、类。

    2. 函数装饰器

    函数装饰器自动添加的代码:
    +----------------------------+----------------------------+
    | @decorator                 | def func():                |
    | def func():                |     ....                   |
    |     ....                   | func = decorator(func)     |
    +----------------------------+----------------------------+
    | func()                     | decorator(func)()          |
    +----------------------------+----------------------------+

    2.1. 装饰器实现

    2.1.1. 函数方式实现

    def decorator(F):
        def tmp_F(*args_for_F):
            这个函数内可以添加任你想执行的代码。
            F(*args_for_F)
        return tmp_F  # 这个返回的是函数地址

    2.1.2. 类方式实现

    class decorator:
        def __init__(self, F):
            self.__func = F
        def __call__(self, *args_for_F):
            self.__func(*args_for_F)
    * 注意:这个方式,被装饰对象如果是类中的函数,则不能正常工作,self的含义发生了变化。

    3. 类装饰器

    类装饰器自动添加的代码:
    +----------------------------+----------------------------+
    | @decorator                 | class C:                   |
    | class C:                   |     ....                   |
    |     ....                   | C = decorator(C)           |
    +----------------------------+----------------------------+
    | C()                        | decorator(C)()             |
    +----------------------------+----------------------------+

    3.1. 装饰器实现

    3.1.1. 函数方式实现

    def decorator(cls):
        class tmp_C:
            def __init__(self, *args):
                  # cls(*args) --> 走的是被装饰类的创建对象流程,然后把返回的对象
                  # 存放在装饰器类实例对象的一个静态属性中。
                self.__instance = cls(*args)
            
            # 最终访问的是装饰器类返回的实例,这个实例的属性与被装饰类实例的属性是
            # 一样的。实现方法就是:属性的传递。
            def __getattr__(self, name):
                return getattr(self.__instance, name)
        return tmp_C
    @decorator
    class Person
        def __init__(self, name, sex):
            self.name = name
            self.sex = sex
                                # 末尾自动加上代码:Person = decorator(Person)
    x = Person('Tim', 'Male')   # x = Person('Tim', 'Male') ---> Person已经
    # 相当于tmp_C了,调用的是tmp_C.__init__ print(x.name) # 调用的是 getattr(Person对象, name), 返回的是:'Tim'

     3.1.2. 类方式实现

    各种实现都存在缺点,推荐使用函数方式。类方式主要特点是考虑,__init__ 会被decorator()调用,对象调用,obj(),会调用decorator.__call__方法。

    4. 装饰器嵌套

    +-------------------------+-------------------------+
    | @A                      |                         |
    | @B                      |                         |
    | @C                      | fc = C(my_func)         |
    | def my_func(..):        | fb = B(fc)              |
    |    ...                  | fa = A(fb)              |
    +-------------------------+-------------------------+
    | @A                      |                         |
    | @B                      |                         |
    | @C                      | cc = C(MyClass)         |
    | class MyClass:          | bc = B(cc)              |
    |    ...                  | ac = A(bc)              |
    +-------------------------+-------------------------+

    5. 装饰器参数

    +----------------------------+----------------------------+
    | @decorator(A,B)            | def func():                |
    | def func():                |     ....                   |
    |     ....                   | f1 = decorator(A,B)        |
    |                            | func = f1(func)            |
    +----------------------------+----------------------------+
    | func()                     | decorator(A,B)(func)()     |
    +----------------------------+----------------------------+
    def decorator(A,B):
        def f1(func):
            def f2(*args_for_func):
                ...
            return f2
        return f1

    6. 总结

    装饰器的核心:通过语法结构,隐藏在被装饰函数之后,需要插入一段固定代码的方法。
    1.  不带参数的装饰器:被装饰对象同名对象 = 装饰器(被装饰对象),运行时顺序:执行装饰器内函数 -> 被装饰函数
    2. 带参数的装饰器:
      • 被装饰对象同名对象 = ( 装饰器(装饰器参数) )(被装饰对象)
      • == 等价于 ==
      • 临时对象 = 装饰器(装饰器参数)  # 会执行装饰器函数,返回中间函数
      • 被装饰对象同名对象 = 临时对象( 被装饰对象 )  # 会执行装饰器内部的函数,并返回最底层一级封装函数
    3. 嵌套装饰器:
      • 被装饰对象同名对象 = ( 最外层装饰器( 中间装饰器... ( 最内层装饰器 ( 被装饰对象 ) ) )
      • == 等价于 ==
      • 最内层装饰后临时对象 = 最内层装饰器 ( 被装饰对象 )  # 会执行装饰器函数,并返回封装函数
      • 中间装饰后临时对象 = 中间装饰器 ( 最内层装饰后临时对象 )  # 会执行装饰器函数,并返回封装函数
      • 被装饰对象同名对象 = 最外层装饰器 ( 中间装饰后临时对象 )  # 会执行装饰器函数,并返回封装函数
      • 运行时顺序:最外侧 -> 中间层 -> 最内层 -> 被装饰函数
  • 相关阅读:
    python-套接字编程之udp
    python-套接字编程之tcp
    用脚本获取windows的mac地址
    电脑控制安卓手机(手机投屏)
    人体内脏分布图
    电子发票打印出来太大了,怎么办?
    局域网内搭建各部门文件共享
    樊登读书会:《善战者说:孙子兵法与取胜法则十二讲》
    健康饮食——百万教程
    减肥十律
  • 原文地址:https://www.cnblogs.com/timlinux/p/9193002.html
Copyright © 2020-2023  润新知