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

    装饰器的功能:在不修改原函数和其调用方式的情况下对原函数功能进行扩展

    装饰器的本质是闭包函数

    求一个函数的运行时间

    import time
    def func():
        start = time.time()
        print('老板好!同事好!大家好!')
        time.sleep(0.01)
        end = time.time()
        print(end-start )
    func()

    但是有多个函数都需要添加此功能时,就会显得很繁琐,此时可以写一个时间函数

    import time
    
    
    def timer(f):
        start = time.time()
        f()
        time.sleep(0.01)
        end = time.time()
        print(end - start)
    
    
    def func():
        print('老板好!同事好!大家好!')
    
    
    timer(func)

    这样不管多少函数都可以调用这个时间函数来计算执行的时间了,但是这样改变了函数的调用方式,原本调用func函数的程序现在要改为调用timer了

    import time
    
    
    def timer(f):
        start = time.time()
        f()
        time.sleep(0.01)
        end = time.time()
        print(end - start)
    
    
    def func():
        print('老板好!同事好!大家好!')
    
    
    func = timer  
    func()          

    这样修改很完美,但是timer函数需要一个参数,如果在赋值的时候传参, func = timer(func),timer函数就直接执行了,并不能实现

    简单的装饰器实现上面的功能

    import time
    
    
    def timer(f):    #装饰器函数
        def inner():
            start = time.time()
            f()  #被装饰的函数
            time.sleep(0.01)
            end = time.time()
            print(end - start)
        return inner
    
    def func():
        print('老板好!同事好!大家好!')
    
    
    func = timer(func)
    func()

    语法糖

    import time
    
    
    def timer(f):
        def inner():
            start = time.time()
            f()
            time.sleep(0.01)
            end = time.time()
            print(end - start)
    
        return inner
    
    
    @timer  # 语法糖 相当于func = timer(func)
    def func():
        print('老板好!同事好!大家好!')
    
    
    # func = timer(func)
    func()

    被装饰的函数有返回值

    import time
    
    
    def timer(f):
        def inner():
            start = time.time()
            ret = f()
            time.sleep( 0.01)
            end = time.time()
            print(end - start)
            return ret
    
        return inner
    
    
    @timer  # 语法糖 相当于func = timer(func)
    def func():
        print('老板好!同事好!大家好!')
        return '新年好'
    
    
    # func = timer(func)
    ret = func()
    print(ret)

    带有参数的被装饰的函数

    import time
    
    
    def timer(f):
        def inner(*args,**kwargs):
            start = time.time()
            ret = f(*args,**kwargs)
            time.sleep( 0.01)
            end = time.time()
            print(end - start)
            return ret
    
        return inner
    
    
    @timer  # 语法糖 相当于func = timer(func)
    def func(a,b,c):
        print('老板好!同事好!大家好!',a,b,c)
        return '新年好'
    
    
    # func = timer(func)
    ret = func(1,2,c=3)  #inner
    print(ret)

    装饰器的固定模式

    def wrapper(f):  # f :被装饰的函数
        def inner(*args, **kwargs):
            # 在被装饰函数之前要做的事
            ret = f(*args, **kwargs)
            # 在被装饰函数之后要做的事
            return ret
    
        return inner
    
    
    @wrapper  # 语法糖 @装饰器的函数名
    def func(a, b, c):  # 被装饰的函数
        print(a, b, c)
        return '新年好'
    
    
    ret = func(1, 2, c=3)
    print(ret)

    查看函数信息的一些方法

    def index():
        '''这是一个主页信息'''
        print('from index')
    
    print(index.__doc__)    #查看函数注释的方法
    print(index.__name__)   #查看函数名的方法

    查看函数的信息

    为函数添加了装饰器,在打印被装饰函数的__name__或__doc__的时候,打印的是装饰器的

    def wrapper(f):  # f :被装饰的函数
        def inner(*args, **kwargs):
            # 在被装饰函数之前要做的事
            ret = f(*args, **kwargs)
            # 在被装饰函数之后要做的事
            return ret
    
        return inner
    
    
    @wrapper  # 语法糖 @装饰器的函数名
    def func(a, b, c):  # 被装饰的函数
        print(a, b, c)
        return '新年好'
    
    print(func.__name__)
    
    打印结果:
    inner

    想要打印被装饰的函数__name__或__doc__,可以使用wraps装饰器

    from functools import wraps
    def wrapper(f):  # f :被装饰的函数
        @wraps(f) #f:被装饰的函数
        def inner(*args, **kwargs):
            # 在被装饰函数之前要做的事
            ret = f(*args, **kwargs)
            # 在被装饰函数之后要做的事
            return ret
    
        return inner
    
    
    @wrapper  # 语法糖 @装饰器的函数名
    def func(a, b, c):  # 被装饰的函数
        print(a, b, c)
        return '新年好'
    
    print(func.__name__)
    
    打印结果:
    func

    带参数的装饰器

    import time
    FLAG = True
    def timer_out(flag):
        def timer(func):
            def inner(*args, **kwargs):
                if flag:
                    start = time.time()
                    ret = func(*args, **kwargs)
                    end = time.time()
                    print(end - start)
                    return ret
                else:
                    ret = func(*args, **kwargs)
                    return ret
    
            return inner
    
        return timer
    
    
    @timer_out(FLAG)
    def beibingyang():
        time.sleep(0.1)
        print('beibingyang')
    
    
    @timer_out(FLAG)
    def erguotou():
        time.sleep(0.1)
        print('erguotou')
    
    
    beibingyang()
    erguotou()

    @timer_out(FLAG) 分为两部分:

    @:为一部分  

    timer_out(FLAG):为一部分

    timer_out(FLAG)执行时返回inner,此时@timer_out(FLAG)为@inner

    @inner 为 beibingyang= timmer(beibingyang)

    当FLAG改为False装饰器就失效了,这样添加和取消都比较便捷

    多个装饰器装饰同一个函数

    def wrapper1(func): #第一步执行后 func=f
        def inner1():
            print('wrapper1 ,before func') #第六步 输出 wrapper1 ,before func
            func() #第七步 调用 f
            print('wrapper1 ,after func') #第八步 输出 wrapper1 ,before func
        return inner1
    
    def wrapper2(func): #第二部执行后 func=inner1
        def inner2():
            print('wrapper2 ,before func') # 第四步 输出 wrapper2 ,before func
            func() #第五部 调用inner1
            print('wrapper2 ,after func') #第九步 输出 wrapper2 ,before func
        return inner2
    
    @wrapper2 #第二步执行 f=wrapper2(f)  返回inner2 f=inner2
    @wrapper1 #第一步执行 f=wrapper1(f) 返回 inner1 f=inner1
    def f():
        print('in f')
    
    f() #第三步执行 f() 此时f为inner2 调用inner2

    打印结果

    wrapper2 ,before func
    wrapper1 ,before func
    in f
    wrapper1 ,after func
    wrapper2 ,after func
  • 相关阅读:
    [Java]获取控制台输入
    数据库行锁实验二,两个同表删除操作不存在交集而不会死锁
    数据库行锁实验一:两个删除操作处理的记录存在交集则会死锁
    Java里如何将一个字符串重复n次
    【json/regex】将嵌套对象生成的json文进行内部整形排序后再输出
    【json/regex】将简单对象生成的json文进行内部排序后再输出
    【maven】在pom.xml中引入对json-lib的依赖dependency
    (转载)使用json-lib进行Java和JSON之间的转换
    【JDBC】仅输入表名和要插入的记录数,自动检测表的字段和类型,然后插入数据的全自动程序(Oracle版)
    【Java/Csv/Regex】用正则表达式去劈分带引号的csv文件行,得到想要的行数据
  • 原文地址:https://www.cnblogs.com/wanglan/p/10306276.html
Copyright © 2011-2022 走看看