zoukankan      html  css  js  c++  java
  • Python核心编程之装饰器

    引入:

    需求:运行函数时得到该函数的名称
    版本一:直接print函数名称
    缺陷:当函数名称发生改变时,print中的内容也需要改变。硬编码
    import inspect
    '''
    转载:https://www.cnblogs.com/cicaday/p/python-decorator.html
    需求:运行函数时得到该函数的名称
    版本一:直接print函数名称
    缺陷:当函数名称发生改变时,print中的内容也需要改变。硬编码
    '''
    def say_hello(): print("hello") def say_goodbye(): print("goodbye") if __name__ == "__main__": say_hello() say_goodbye()
    版本二:调用inspect模块中的stack()方法,获取函数名称
    缺陷:调用debug()方法多次
    import inspect
    '''
    需求:运行函数时得到该函数的名称
    版本二:调用inspect模块中的stack()方法,获取函数名称
    缺陷:调用debug()方法多次
    '''
    def debug():
        caller_name = inspect.stack()
        print("caller_name: " + caller_name[1][3])
    
    def say_hello():
        debug()
        print("hello")
    def say_goodbye():
        debug()
        print("goodbye")
    
    if __name__ == "__main__":
        say_hello()
        say_goodbye()

    装饰器:

    版本三:装饰器
    ---------装饰器:装饰器的作用就是为已经存在的函数或对象添加额外的功能。
        装饰器本质上是一个Python函数,它可以让其他函数
        在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值
        也是一个函数对象。它经常用于有切面需求的场景,
        比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
        装饰器是解决这类问题的绝佳设计,有了装饰器,
        我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
    '''

    一、不带参数的装饰器

    import inspect
    '''
    需求:运行函数时得到该函数的名称
    版本四:装饰器
    ---------装饰器:装饰器的作用就是为已经存在的函数或对象添加额外的功能。
        装饰器本质上是一个Python函数,它可以让其他函数
        在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值
        也是一个函数对象。它经常用于有切面需求的场景,
        比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
        装饰器是解决这类问题的绝佳设计,有了装饰器,
        我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
    @log
    def a():
      pass
    @log语法糖知识告诉python解释器插入代码:a = log(a)
    '''
    def debug(func):
        def wrapper():
            print("callner_name:" + func.__name__)
            return func()
        return wrapper

    # say_hello = debug(say_hello) = wrapper @debug
    def say_hello(): print("hello")
    # say_goodbye = debug(say_goodbye) = wrapper @debug
    def say_goodbye(): print("goodbye") if __name__ == "__main__": say_hello() print('say_hello()实际调用的函数:'+ say_hello.__name__) say_goodbye() print('say_goodbye()实际调用的函数:'+ say_goodbye.__name__)
    '''运行结果
    callner_name:say_hello
    hello
    say_hello()实际调用的函数:wrapper
    callner_name:say_goodbye
    goodbye
    say_goodbye()实际调用的函数:wrapper
    '''

    二、带参数的装饰器

    import inspect
    '''
    装饰器传参数
    理解*args, **kwargs: splat运算符* **
    *args: 将传入的位置参数打包成元组(可变参数)
    **kwargs: 将传入的关键字参数打包成字典(可选参数)
    
    到这里已经掌握了初级装饰器的写法
    '''
    def add_sum(*args):
        print(args)
        print(type(args))
    
    def add_s(**kwargs):
        print(kwargs)
        print(type(kwargs))
        for key, value in kwargs.items():
            print(f"{key}:{value}")
    
    def debug(func):
        def wrapper(*args, **kwargs):  # 宇宙无敌参数
            print("callner_name:" + func.__name__)
            return func(*args, **kwargs)
        return wrapper
    @debug
    def say_hello(somthing):
        print(f"hello{somthing}")
    
    @debug
    def say_goodbye(something):
        print(f"goodbye{something}")
    
    
    if __name__ == "__main__":
        add_sum(1, 2, 3, 4, 5)
        add_s(a=1, b=2, c=3)
        print(*[1, 2, 3, 4])
        print(*{'a': 1, 'b': 2, 'c': 3})
        say_hello('!')
        say_goodbye('!')
    '''运行结果
    (1, 2, 3, 4, 5)
    <class 'tuple'>
    {'a': 1, 'b': 2, 'c': 3}
    <class 'dict'>
    a:1
    b:2
    c:3
    1 2 3 4
    a b c
    callner_name:say_hello
    hello!
    callner_name:say_goodbye
    goodbye!
    '''

    三、不带参数的类装饰器

    import inspect
    '''
    基于类实现的装饰器(不带参数):callable 可以调用
        装饰器函数其实是这样一个接口约束,
    它必须接受一个callable对象作为参数,
    然后返回一个callable对象。
    在Python中一般callable对象都是函数,
    但也有例外。只要某个对象重载了__call__()方法,
    那么这个对象就是callable的。
    '''
    class Test():
        def __call__(self, *args, **kwargs):
            print('call me')
    
    class logging(object):
        def __init__(self, func):
            self.func = func
    
        # 内置方法
        def __call__(self, *args, **kwargs):
            print("[DEBUG]: enter function {func}()".format(
                func=self.func.__name__))
            return self.func(*args, **kwargs)
    @logging
    def say(something='Toney'):
        print("say {}!".format(something))
    
    # say = logging(say)
    # say(something='Toney')  --> 执行内置方法
    if __name__ == "__main__":
       t = Test()
       t()
       say()
    '''运行结果
    call me
    [DEBUG]: enter function say()
    say Toney!
    '''
     

    四、带参数的类装饰器

    import inspect
    '''
    带参数的类装饰器
    '''
    class logging(object):
        def __init__(self, level):
            self.level = level
    
        def __call__(self, func):
            def wrapper(*args, **kwargs):
                print("[DEBUG]: enter function {level}()".format(
                    level=self.level))
                func(*args, **kwargs)
            return wrapper
    @logging(level = 'INFO')
    def say(something='Toney'):
        print("say {}!".format(something))
    # say = logging(level = 'INFO')
    # say = say(something='Toney') --> say = wrapper
    if __name__ == "__main__":
       say()
    
    '''运行结果
    [DEBUG]: enter function INFO()
    say Toney!
    '''
    
    
    需求:运行函数时得到该函数的名称
    版本一:直接print函数名称
  • 相关阅读:
    模板 无源汇上下界可行流 loj115
    ICPC2018JiaozuoE Resistors in Parallel 高精度 数论
    hdu 2255 奔小康赚大钱 最佳匹配 KM算法
    ICPC2018Beijing 现场赛D Frog and Portal 构造
    codeforce 1175E Minimal Segment Cover ST表 倍增思想
    ICPC2018Jiaozuo 现场赛H Can You Solve the Harder Problem? 后缀数组 树上差分 ST表 口胡题解
    luogu P1966 火柴排队 树状数组 逆序对 离散化
    luogu P1970 花匠 贪心
    luogu P1967 货车运输 最大生成树 倍增LCA
    luogu P1315 观光公交 贪心
  • 原文地址:https://www.cnblogs.com/854594834-YT/p/13795614.html
Copyright © 2011-2022 走看看