day14装饰器

泄露秘密 提交于 2020-03-30 17:31:36
  1. 开放封闭原则:

    • 开放:对源码的拓展是开放的。
    • 封闭:对源码的修改是封闭的。
  2. 装饰器:完全遵循开放封闭原则,即在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。(装饰器的本质是闭包)

    • 举例:计算func1函数的运行效率。
    def func1():
        for i in range(10000):
            i+=1
    

    此问题相当于为函数func1增加一个方法,可以计算函数的运行时间。用简单的time模块就可以完成,如下:

    import time
    time.perf_counter()
    func1()
    print(f'程序运行的时间为:{time.perf_counter()}')
    

    但这样做不满足开放封闭原则,可更改为如下:

    import time
    def timer(f):
        def inner():
    		time.perf_counter()
            f()
            print(f'程序运行的时间为:{time.perf_counter()}')
        return inner
    func1=timer(func1)
    func1()   #这样在不改变原函数的调用方式下为原函数增加了新的功能。即为原始的装饰器模型。在运行大型平台时非常有用。
    
    #装饰器的本质是闭包
    import time
    def timer(f):
        f=func1   #f为自由变量,指向函数func1的内存地址。
        def inner():
    		time.perf_counter()
            f()
            print(f'程序运行的时间为:{time.perf_counter()}')
        return inner
    func1=timer(func1)
    func1() 
    

    但如果想要测试另一个函数(例如func3)的效率,则仍然需要增加一句语法:func3=timer(func3)。假设要测试的函数过多的话,就会比较麻烦。

  3. 原始装饰器模型的升级版本:python做了一个优化,提出了一个‘语法糖’的概念。即在编写了装饰器后,需要将装饰器代码放在所有代码的前方。

    import time
    #装饰器函数
    def timer(f):
        def inner():
    		time.perf_counter()
            f()
            print(f'程序运行的时间为:{time.perf_counter()}')
        return inner
    
    
    #当要对装饰器函数调用时,在要装饰函数的前方使用@+装饰器函数名,如下:
    
    
    @timer    #相当于func1=timer(func1)
    def func1():
        for i in range(10000):
            i+=1
            
    func1()
    
    
    #此时即使有func3,也可以直接在函数前调用装饰器:
    @timer      #会将两行并为一行读取:func3=timer(func3)
    def func3():
        pass
    
  4. 当函数有返回值时(被装饰函数有返回值时):

    import time
    #装饰器函数
    def timer(f):
        def inner():
    		time.perf_counter()
            f()
            print(f'程序运行的时间为:{time.perf_counter()}')
        return inner
    
    @timer
    def func1():
        for i in range(10000):
            i+=1
        return i
    print(func1())    #None,无法打印出函数func1的返回值。
    

    此时要对装饰器进行改进:

    import time
    #装饰器函数
    def timer(f):
        def inner():
    		time.perf_counter()
            r = f()    #将返回值赋值给r
            print(f'程序运行的时间为:{time.perf_counter()}')
            return r   #将返回值给inner函数。
        return inner
    
    @timer
    def func1():
        for i in range(10000):
            i+=1
        return i
    print(func1())     #10000
    

    加上装饰器不应该改变原函数的返回值,所有func1的返回值i应该返回给inner函数。

  5. 当函数有参数时(被装饰函数带参数):

    import time
    #装饰器函数
    def timer(f):
        def inner(*arg,**kargs):      #*的聚合
    		time.perf_counter()  
            r = f(*arg,**kargs)       #*的打散   ,并将返回值传给inner函数。
            print(f'程序运行的时间为:{time.perf_counter()}')
            return r   #将返回值给inner函数。
        return inner
    
    @timer
    def func1(num1,num2):
        for i in range(num1,num2):
            i+=1
        return i
    print(func1())     #
    
  6. 标准版的装饰器:

    def wrapper(f):
        def inner(*arg,**kargs):
            '''添加额外的功能:执行被装饰函数之前的操作'''
            ret = f(*arg,**kargs)
            '''添加额外的功能:执行被装饰函数之前的操作'''
            return ret
        return inner
    
    #装饰器的调用
    @wrapper
    def func():
        pass
    
  7. 装饰器的应用:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!