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函数名称
  • 相关阅读:
    laravel excel 导入
    linux 怎么解压
    mysql分表和表分区详解
    mysql主从复制windows-》linux
    Redis和Memcache的区别
    mysql group by 用法解析(详细)
    [置顶] mysql常用函数
    mysql测试数据库employees一些sql语句
    session入mysql
    session入库
  • 原文地址:https://www.cnblogs.com/854594834-YT/p/13795614.html
Copyright © 2011-2022 走看看