欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

day14装饰器

程序员文章站 2022-03-26 11:40:52
1. 开放封闭原则: + 开放:对源码的拓展是开放的。 + 封闭:对源码的修改是封闭的。 2. 装饰器:完全遵循开放封闭原则,即在 不改变 原函数的代码以及 调用方式 的前提下,为其 增加新的功能 。(装饰器的本质是闭包) + 举例:计算func1函数的运行效率。 此问题相当于为函数func1增加一 ......
  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. 装饰器的应用: