• python学习之装饰器


    4.9 装饰器

    4.9.1 开放封闭原则

    ​ 1.对扩展是开放的:允许代码扩展、添加新功能。

    ​ 2.对修改是封闭的:不要改变源码。防止对函数内部进行修改,不能改变调用方式

    4.9.2 装饰器初识

    定义:在不改变原被装饰的函数的源代码以及调用方式下,为其添加一个额外的功能。

    装饰器本身是一个函数

    版本一:
    import time
    
    def index():
        time.sleep(2)
        print('装饰器')
    
    def func(f):
        def inner():
            start_time = time.time()    #格林威治时间
            f()
            end_time = time.time()
            print(f"执行时间为{end_time - start_time}")
        return inner
    index()
    index = func(index)
    index()   #实际执行的是inner()
    

    上边两个 index() 输出的结果是不一样的,第二个index()的功能已经增加

    这么做的优点在于:没有改变index的执行方式,如果整个py文件里调用了100次index(),只需要这一步函数,不重要其他的修改,就可以神不知鬼不觉地进行了功能上的升级。

    版本二:带自由变量的装饰器
    import time
    
    def index():
        time.sleep(2)
        print('装饰器')
    
    def func(f):
        f = index  # 自由变量 f 存在的内存地址与全局和临时空间并列,不会因为函数的结束而消失,对其的赋值必须是要修饰的函数的变量名,因为在内部函数时要执行,此时它接收到的时函数index指向的内存地址
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print(f"执行时间为{end_time - start_time}")
    
        return inner
    
    index = func(index)
    index()  #实际执行的是inner()
    
    版本三:语法糖装饰器(标准版)

    一般情况下,应该把装饰器函数放在需要加装饰器的函数之上

    @装饰器名 放在需要加装饰器的函数名上边

    # 语法糖装饰器
    import time
    
    # func装饰器
    def func(f):
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print(f"执行时间为{end_time - start_time}")
    
        return inner
    
    @func  # 等同于 index = func(index)
    def index():
        time.sleep(2)
        print('装饰器')
    
    def copare():
        time.sleep(2)
        print('比较用的')
    
    index()  #实际执行的是inner()
    copare()
    

    4.9.3 带返回值的修饰器

    如果原函数带返回值怎么办?对于前边介绍的几种装饰器实际运行时的index()其实执行的是inner()内部函数,而原来的index含糊的返回值实际上是给了f(),所以如果添加装饰器后,要保持原函数的返回值,就要把f()接受的数值当成inner的返回值,有点绕,代码如下:

    import time
    
    # func装饰器
    def func(f):
        def inner():
            start_time = time.time()
            s = f()
            print(s)    #检验:f()实际上执行的是被装饰的原函数,是有返回值的
            end_time = time.time()
            print(f"执行时间为{end_time - start_time}")
            return s
        return inner
    
    @func  # 等同于 index = func(index)
    def index():
        time.sleep(2)
        print('装饰器')
        return 3
    @func
    def copare():
        time.sleep(2)
        print('比较用的')
        return 4
    
    print(index())
    print(copare())
    
    #输出装饰器
    3             #f()调用的函数的返回值
    执行时间为2.0006275177001953
    3
    比较用的
    4	         #f()调用的函数的返回值
    执行时间为2.0006816387176514
    4如下:
    
    
    

    4.9.4带参数的装饰器

    import time
    
    # func装饰器
    def func(f):   #这里的f是被修饰的函数
        def inner(*args,**kwargs):   #函数的定义,*,**的作用是聚合参数,这里使用动态参数是因为不知道被修饰函数到底有多少参数
            start_time = time.time()
            s = f(*args,**kwargs)    #含糊的执行,*,**的作用是打散参数
            end_time = time.time()
            print(f"执行时间为{args,kwargs}")
            return s      #返回被修饰函数的返回值
        return inner
    
    @func  # 等同于 index = func(index)
    def index(argv):
        time.sleep(2)
        print(argv)
        return 3
    @func
    def copare(argv):
        time.sleep(2)
        print(argv)
        return 4
    
    print(index('haha'))
    print(copare('xixi'))
    #输出
    haha
    执行时间为(('haha',), {})
    3
    xixi
    执行时间为(('xixi',), {})
    4
    
    
    

    4.9.5标准版装饰器

    结构如下:

    def wrapper(func):                	#func是被修饰的函数,wrapper是外层函数
        def inner(*args,**kwargs):    	#定义的额内层函数,*  **的作用是聚合参数
            '''执行被装饰函数之前的操作'''
            ret = func                	#被修饰函数的执行,可以使用*  **打散函数
            '''执行被装饰函数之后的操作'''
            return ret                	#返回被修饰函数的返回值
        return inner                  	#返回被修饰函数
    

    4.9.6 带参数的装饰器***

    def outer(flag):
        def timer(func):
            def inner(*args,**kwargs):
                if flag:
                    print('''执行函数之前要做的''')
                re = func(*args,**kwargs)
                if flag:
                    print('''执行函数之后要做的''')
                return re
            return inner
        return timer
    
    @outer(False)
    def func():
        print(111)
    
    func()
    

    4.9.7 多个装饰器修饰一个函数

    def wrapper1(func):
        def inner():
            print('wrapper1 ,before func')
            func()
            print('wrapper1 ,after func')
        return inner
    
    def wrapper2(func):
        def inner():
            print('wrapper2 ,before func')
            func()
            print('wrapper2 ,after func')
        return inner
    
    @wrapper2
    @wrapper1
    def f():
        print('in f')
    
    f()
    #输出
    wrapper2 ,before func
    wrapper1 ,before func
    in f
    wrapper1 ,after func
    wrapper2 ,after func
    

    原则:从上到下再从下到上;从外到内再从内到外
    流程如下:

    仅供参考,欢迎指正
  • 相关阅读:
    工厂模式之抽象工厂
    c#中的Task异步编程
    c# 异步编程
    工厂模式之工厂方法模式
    c# 多线程——入门学习
    代理模式
    工厂模式之简单工厂
    SOA面向服务架构
    [LeetCode]387. 字符串中的第一个唯一字符
    [LeetCode]7. 整数反转
  • 原文地址:https://www.cnblogs.com/jjzz1234/p/11084572.html
Copyright © 2020-2023  润新知