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

    1. 装饰器的基本知识

    < 函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖 = 装饰器 >

    1.1. 装饰器的概念

    装饰器实际上就是为了给某程序增添功能,但该程序已经上线或已经被使用,那么就不能大批量的修改源代码,这样是不科学的也是不现实的,因为就产生了装饰器,使得其满足:

    1. 不能修改被装饰的函数的源代码
    2. 不能修改被装饰的函数的调用方式
    3. 满足1、2的情况下给程序增添功能

    1.2. 装饰器的作用

    • 日志
    • 检查(文件是否存在,自动命名)
    • 认证
    • 计时
    • 路由
    • 发邮件

    1.3. 装饰器的类型

    • 单重
    • 多重--多重的装饰器一般用不到
    • 装饰器带参数(多一层封装,传入参数)
    • 类的装饰器
    • 官方工具:wraps:保留原函数的名字和说明

    1.4. 装饰器的执行次序

    装饰器在运行时导入,正常函数执行时从上到下,相互调用。
    在其他文件中引用这个文件,会自动执行装饰器。

    2. 装饰器学习

    2.1. 无参数版本装饰器

    
    def deco_iron(func):
        def inner():  # 使用且套函数,并返回是为了解决被装饰函数运行两次的问题
            print('开始准备变身')
            func()
            print('变身结束')
        return inner
    
    @deco_iron  # 其实就是 tony = deco_iron(tony)
    def tony():
        print('toney运行函数:', tony.__name__)
    
    # tony = deco_iron(tony)  # 这句其实就是装饰器 语法糖, 在其他代码中引用,会先运行这个
    
    def main():
        tony()
    
    if __name__ == '__main__':
        main()
    
    

    2.2. 被装饰函数带参数版本

    1. 先装饰函数名
    2. 为嵌套函数inner传递参数-因为在最终调用的tony其本质是inner,所以在inner接受函数
    
    # coding=utf-8
    
    def deco_iron(func):
        def inner(*args, **kwargs):  # 使用且套函数,并返回是为了解决被装饰函数运行两次的问题
            print('开始准备变身', func.__name__)
            print(args, kwargs)
            func(*args, **kwargs)
            print('变身结束', func.__name__)
        return inner  # 被装饰的函数,其实是变成了这个,所以传递参数是传给inner
    
    @deco_iron  # 其实就是 tony = deco_iron(tony)
    def tony(name, age, dic):
        print('toney运行函数:', tony.__name__)  # 这里的name发生了变化,因为这个tony被装饰后,变成了inner,后面需要解决这个问题
    
    # tony = deco_iron(tony)  # 这句其实就是装饰器 语法糖, 在其他代码中引用,会先运行这个
    
    def main():
        tony('hui', 12, {'city': 'hz', 'name': 'hui'} ) # 这里的tony 其实变成了inner
    
    if __name__ == '__main__':
        main()
    
    

    2.3. 装饰器带参数版本

    装饰器带参数需要在上面的版本的外面再且套一层函数

    # coding=utf-8
    def outer(name):
        def deco_iron(func):
            def inner(*args, **kwargs):  # 使用且套函数,并返回是为了解决被装饰函数运行两次的问题
                print('开始准备变身', func.__name__)
                print(args, kwargs)
                func(*args, **kwargs)
                print(name)
                print('变身结束', func.__name__)
            return inner  # 被装饰的函数,其实是变成了这个,所以传递参数是传给inner
        return deco_iron
    
    @outer('小辣椒')  # 其实就是 tony = deco_iron(tony)
    def tony(name, age, dic):
        print('toney运行函数:', tony.__name__)  # 这里的name发生了变化,因为这个tony被装饰后,变成了inner
    
    # tony = deco_iron(tony)  # 这句其实就是装饰器 语法糖, 在其他代码中引用,会先运行这个
    
    def main():
        tony('hui', 12, {'city': 'hz', 'name': 'hui'} ) # 这里的tony 其实变成了inner
    
    if __name__ == '__main__':
        main()
    

    2.4. 解决传递函数变化

    主要使用python中的内置函数wraps。
    其本质是 func.name = tony.name 其他的类似

    # coding=utf-8
    
    from functools import wraps  #
    def outer(name):
        def deco_iron(func):
            @wraps(func)  #解决传递函数,函数名变化等问题'''
            def inner(*args, **kwargs):  # 使用且套函数,并返回是为了解决被装饰函数运行两次的问题
                print('开始准备变身', func.__name__)
                print(args, kwargs)
                func(*args, **kwargs)
                print(name)
                print('变身结束', func.__name__)
            return inner  # 被装饰的函数,其实是变成了这个,所以传递参数是传给inner
        return deco_iron
    
    @outer('小辣椒')  # 其实就是 tony = deco_iron(tony)
    def tony(name, age, dic):
        '''被修饰的函数'''
        print('toney运行函数:', tony.__name__)  # 这里的name发生了变化,因为这个tony被装饰后,变成了inner
        print('toney函数的doc', tony.__doc__)
    # tony = deco_iron(tony)  # 这句其实就是装饰器 语法糖, 在其他代码中引用,会先运行这个
    
    def main():
        tony('hui', 12, {'city': 'hz', 'name': 'hui'} ) # 这里的tony 其实变成了inner
    
    if __name__ == '__main__':
        main()
    

    2.5. 封装成类

    使用技术:
      类() 调用初始化__init__
      对象() 调用__call__

    3. 实际案例

  • 相关阅读:
    bzoj1318[spoj 744] Longest Permutation
    bzoj2146 Construct
    bzoj2448 挖油
    bzoj3961[WF2011]Chips Challenge
    bzoj4152[AMPPZ2014] The Captain
    AtCoder Regular Contest 076E Coneected?
    Codeforces 748D Santa Claus and a Palindrome
    bzoj3572[HNOI2014]世界树
    SQL SERVER 字段统一补0方法
    SSRS运行report builder报错 的解决方案
  • 原文地址:https://www.cnblogs.com/louhui/p/9230984.html
Copyright © 2011-2022 走看看