zoukankan      html  css  js  c++  java
  • Python入门day17——装饰器

    装饰器

    1、什么是装饰器

    装饰器指的定义一个函数,该函数是用来为其他函数添加额外的功能

    2、为何要用装饰器

    装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能

    遵循开放封闭原则:
    开放:指的是对拓展功能是开放的
    封闭:指的是对修改源代码是封闭的

    3、如何用装饰器

    需求:在不修改index函数的源代码以及调用方式的前提下为其添加统计运行时间的功能

    def index(x,y):
        time.sleep(3)
        print('index %s %s' %(x,y))
    
    index(111,222)
    

    解决方案一:在函数内部增加功能

    # 问题:没有修改被装饰对象的调用方式,但是修改了其源代码,失败
    import time
    
    def index(x,y):
        start=time.time()
        time.sleep(3)
        print('index %s %s' %(x,y))
        stop = time.time()
        print(stop - start)
        
    index(111,222)
    
    # 结果
    index 111 222
    3.0009360313415527
    

    解决方案二:在全局空间调用index函数前后增加代码

    # 问题:没有修改被装饰对象的调用方式,也没有修改了其源代码,并且加上了新功能,但是没调用一次index函数就要写一次,代码冗余
    import time
    
    def index(x,y):
        time.sleep(3)
        print('index %s %s' %(x,y))
    
    start=time.time()
    index(111,222)
    stop=time.time()
    print(stop - start)
    
    start=time.time()
    index(33,44)
    stop=time.time()
    print(stop - start)
    
    start=time.time()
    index(55,66)
    stop=time.time()
    print(stop - start)
    
    # 结果
    index 111 222
    3.0004470348358154
    index 33 44
    3.000368118286133
    index 55 66
    3.0004358291625977
    

    解决方案三:将功能代码封装进函数

    # 问题:解决了方案二代码冗余问题,但带来一个新问题即函数的调用方式改变了
    import time
    
    def index(x,y):
        time.sleep(3)
        print('index %s %s' %(x,y))
    
    def wrapper():
        start=time.time()
        index(111,222)
        stop=time.time()
        print(stop - start)
    
    wrapper()
    
    # 结果
    index 111 222
    3.000734806060791
    

    大方向:如何在方案三的基础上不改变函数的调用方式

    解决方案三的优化一:在wrapper函数中加入参数

    # 方案三的优化一:可以给index灵活传参,新的问题是,只能给index增加功能
    import time
    
    def index(x,y,z):
        time.sleep(3)
        print('index %s %s %s' %(x,y,z))
    
    def wrapper(*args,**kwargs):
        start=time.time()
        index(*args,**kwargs) # index(3333,z=5555,y=44444)
        stop=time.time()
        print(stop - start)
    
    wrapper(1,2,3)
    
    # 结果
    index 1 2 3
    3.00087833404541
    

    解决方案三的优化二:给wrapper函数变成闭包函数

    # 方案三的优化二:外层函数传入参数,将wrapper内的函数调用变成外层函数的参数,在优化一的基础上把被装饰对象写活了,原来只能装饰index,新的问题是原函数有返回值,调用函数的时候无返回值
    import time
    
    def index(x,y,z):
        time.sleep(3)
        print('index %s %s %s' %(x,y,z))
    
    def home(name):
        time.sleep(2)
        print('welcome %s to home page' %name)
    	res 123
    def outter(func):
        # func = index的内存地址
        def wrapper(*args,**kwargs):
            start=time.time()
            func(*args,**kwargs) # index的内存地址()
            stop=time.time()
            print(stop - start)
        return wrapper
    
    index=outter(index) # index=wrapper的内存地址
    home=outter(home) # home=wrapper的内存地址
    
    index(2,3,4)
    home('yu')
    res=home()
    print(res)
    # 结果
    index 2 3 4
    3.0005781650543213
    welcome yu to home page
    2.0014724731445312
    None
    

    解决方案三的优化三:给函数wrapper以返回值

    # 方案三的优化三:将wrapper做的跟被装饰对象一模一样,以假乱真
    import time
    
    def index(x,y,z):
        time.sleep(3)
        print('index %s %s %s' %(x,y,z))
    
    def home(name):
        time.sleep(2)
        print('welcome %s to home page' %name)
    
    def outter(func):
        def wrapper(*args,**kwargs):
            start=time.time()
            res=func(*args,**kwargs)
            stop=time.time()
            print(stop - start)
            return res
        return wrapper
    
    
    
    # 偷梁换柱:home这个名字指向的wrapper函数的内存地址
    home=outter(home)
    
    res=home('yu') # res=wrapper('yu')
    print('返回值--》',res)
    
    # 结果
    welcome egon to home page
    2.000577926635742
    返回值--》 None
    
    语法糖:让你开心的语法
    import time
    # 装饰器
    def timmer(func):
        def wrapper(*args,**kwargs):
            start=time.time()
            res=func(*args,**kwargs)
            stop=time.time()
            print(stop - start)
            return res
        return wrapper
    
    # 在被装饰对象正上方的单独一行写@装饰器名字
    @timmer # index=timmer(index)
    def index(x,y,z):
        time.sleep(3)
        print('index %s %s %s' %(x,y,z))
    
    @timmer # home=timmer(ome)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page' %name)
    
    index(x=1,y=2,z=3)
    home('yu')
    
    # 结果
    index 1 2 3
    3.0008275508880615
    welcome yu to home page
    2.0004775524139404
    # 总结无参装饰器模板
    def outter(func):
        def wrapper(*args,**kwargs):
            # 1、调用原函数
            # 2、为其增加新功能
            res=func(*args,**kwargs)
            return res
        return wrapper
    ```python
    #偷梁换柱,即将原函数名指向的内存地址偷梁换柱成wrapper函数
    #        所以应该将wrapper做的跟原函数一样才行
    def outter(func):
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs) # res=index(1,2)
            return res
        return wrapper
    @outter # index=outter(index)
    def index(x,y):
        """这个是主页功能"""
        print(x,y)
    
    print(index.__name__) # 指向的是wrapper的内存地址的名字
    print(index.__doc__)  # wrapper内没有注释功能 所以返回None
    
    # 结果
    wrapper
    None
    1 2
    
    def outter(func):
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs) # res=index(1,2)
            return res
        # 手动将原函数的属性赋值给wrapper函数
        # 1、函数wrapper.__name__ = 原函数.__name__
        # 2、函数wrapper.__doc__ = 原函数.__doc__
        wrapper.__name__ = func.__name__
        wrapper.__doc__ = func.__doc__
        return wrapper
    @outter # index=outter(index)
    def index(x,y):
        """这个是主页功能"""
        print(x,y)
    
    print(index.__name__) 
    print(index.__doc__)
    
    # 结果
    index
    这个是主页功能
    1 2
    
    def outter(func):
        @wraps(func) # 将原函数的属性赋值给wrapper函数 装饰器作用
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs) # res=index(1,2)
            return res
        return wrapper
    @outter # index=outter(index)
    def index(x,y):
        """这个是主页功能"""
        print(x,y)
    
    print(index.__name__)
    print(index.__doc__)
    
    # 结果
    index
    这个是主页功能
    1 2
    
  • 相关阅读:
    我的作业
    代码练习
    prority_queue 的用法 实例
    最短路问题专题
    键值对 Intent
    P103 任意两点之间的最短路问题 Floyd_warshall算法
    第6届山东省ACM省赛总结
    HDU 3247 Resource Archiver[AC自动机+最短路+dp]
    POJ 2778 DNA Sequence [AC自动机 + 矩阵快速幂]
    HDU 2896 病毒侵袭 [AC自动机]
  • 原文地址:https://www.cnblogs.com/yding/p/12554222.html
Copyright © 2011-2022 走看看