• python全栈-Day 12


    一、完美的装饰器(纠正装饰器的函数指向)

    1、装饰器的前后执行的解释

    def wrapper(f):
        def inner(*args,**kwargs):  #定义函数的时候,属于接收参数,此时  *args,**kwargs聚合为元组,字典
            print('装饰在函数前的')
            print(args)  #args参数本身,依旧是 元组
            print(*args)
            ret = f(*args,**kwargs)  #调用函数的时候,属于使用参数,此时  *args,**kwargs拆分为元组的各元素,字典的各key-value
            print('装饰在函数后的')
            return ret
        return inner
    
    @wrapper   #fun = wrapper(fun)    #装饰器只是一个传话的媒介
    def fun(a,b):
        print('fun开始了')
        print('a',a)
        print('b',b)
        return 'fun返回值'
    
    re = fun('wangjing',1234)
    print(re)

    2、此处添加2个知识点

    def wahaha():
        '''
        一个打印娃哈哈的函数
        :return:
        '''
        print('娃哈哈')
    
    print(wahaha.__name__)   #函数的名称的字符串格式
    print(wahaha.__doc__)   #函数的注释
    import os
    print(os.path.getsize('web_cache') )  #获取文件大小
    

    3、查看基本的装饰器对 原函数产生的变化

    注意结果中的 fun.__name__ 的值已经变成了inner!!!!也就是说虽然添加了装饰器wrapper的功能,但是fun函数已经不存在,而是变成了inner

    def wrapper(f):
        def inner(*args,**kwargs):  #定义函数的时候,属于接收参数,此时  *args,**kwargs聚合为元组,字典
            '''
            这是inner自己的注释
            :param args:
            :param kwargs:
            :return:
            '''
            print('装饰在函数前的')
            print(args)  #args参数本身,依旧是 元组
            print(*args)
            ret = f(*args,**kwargs)  #调用函数的时候,属于使用参数,此时  *args,**kwargs拆分为元组的各元素,字典的各key-value
            print('装饰在函数后的')
            return ret
        return inner
    
    @wrapper   #fun = wrapper(fun)    #装饰器只是一个传话的媒介
    def fun(a,b):
        '''
        这是fun原来的的注释
        :param a:
        :param b:
        :return:
        '''
        print('fun开始了')
        print('a',a)
        print('b',b)
        return 'fun返回值'
    
    re = fun('wangjing',1234)
    print(re)
    print(fun.__name__)    #实际上fun的函数名已经变成了inner,因为在全局名字空间中没有fun的函数名,fun作为wrapper的参数存储
    

     4、添加一个第三方的装饰器,使fun函数完全不变化,依旧是他本身。即在inner函数上添加 一个第三方的带参数的装饰器

    from functools import wraps
    def wrapper(f):
        @wraps(f)    #是一个第三方的装饰器,作用是 完全不改变fun的本质,但是依旧可以实现装饰器wrapper的功能
        def inner(*args,**kwargs):  #定义函数的时候,属于接收参数,此时  *args,**kwargs聚合为元组,字典
            '''
            这是inner自己的注释
            :param args:
            :param kwargs:
            :return:
            '''
            print('装饰在函数前的')
            print(args)  #args参数本身,依旧是 元组
            print(*args)
            ret = f(*args,**kwargs)  #调用函数的时候,属于使用参数,此时  *args,**kwargs拆分为元组的各元素,字典的各key-value
            print('装饰在函数后的')
            return ret
        return inner
    
    @wrapper   #fun = wrapper(fun)    #装饰器只是一个传话的媒介
    def fun(a,b):
        '''
        这是fun原来的的注释
        :param a:
        :param b:
        :return:
        '''
        print('fun开始了')
        print('a',a)
        print('b',b)
        return 'fun返回值'
    
    re = fun('wangjing',1234)
    print(re)
    print(fun.__name__)    #此时fun的函数名依旧是本身的fun
    

    二、带参数的装饰器

    给个场景:给函数计算执行时间,之后可能又把这些装饰作用在全部函数中删除

    1、先写一个函数:不包含集体删除的功能,写一个装饰器可计算函数执行时间

    import time
    def timer(func):
        def inner(*args,**keargs):
            start = time.time()
            ret = func(*args,**keargs)
            end = time.time()
            print(end - start)
            return ret
        return inner
    
    @timer
    def wahaha():
        time.sleep(0.1)
        print('wahaha')
    
    @timer
    def shuangww():
        time.sleep(0.2)
        print('shuangww')
    
    wahaha()
    shuangww()
    

     2、再写一个函数:包含集体删除的功能,写一个装饰器可计算函数执行时间,并且可以通过一个布尔变量的值 控制是否进行删除的功能

    import time
    flag = False
    def timer_out(flag):
        def timer(func):
            def inner(*args,**keargs):
                if flag:
                    start = time.time()
                    ret = func(*args,**keargs)
                    end = time.time()
                    print(end - start)
                    return ret
                else:
                    ret = func(*args,**keargs)
                    return ret
            return inner
        return timer
    
    @timer_out(flag)  #装饰器的 函数名=括号,则代表函数执行,先执行函数(timer = timer_out(flag))再进行装饰器操作(实际上等于 @timer,即wahaha = timer(wahaha))
    def wahaha():
        time.sleep(0.1)
        print('wahaha')
    
    @timer_out(flag)
    def shuangww():
        time.sleep(0.2)
        print('shuangww')
    
    wahaha()
    shuangww()
    

     3、最后凑数总结一下逻辑走向

    在1中的装饰器的外层再加一个函数,该函数有一个 参数flag,返回值为 timer函数~~

    装饰器的装饰方式改为:@timer_out(flag)

    装饰器的 函数名=括号,则代表函数执行,先执行函数(timer = timer_out(flag))再进行装饰器操作(实际上等于 @timer,即wahaha = timer(wahaha))

    三、多个装饰器装饰一个函数

    def wrapper1(func):  #func-->innner2
        def inner1():
            print('inner1:before func')
            func()   #f
            print('inner1:after func')
        return inner1
    
    def wrapper2(func):  #func-->f
        def inner2():
            print('inner2:before func')
            func()
            print('inner2:after func')
        return inner2
    
    @wrapper1
    @wrapper2
    def f():
        print('f被执行了')
    
    f()
    

     最后凑一下逻辑走向:

    1、把wrapper1放到内存里

    2、把wrapper2放到内存里

    3、处理装饰器,按照从上到下的执行原则,走到@wrapper1,但是装饰器必须得找到距离最近的函数才能真正发生作用,因此走到了@wrapper2,即 

    f = wrapper2(f)== inner2

    此时wrapper1的形参func指向了f

    4、之后由于最近的函数已经找到了,所以再执行@wrapper1,此时f已经指向inner2了,此时所以

    #f = wrapper1(f)-->wrapper1(inner2)== inner1

    此时wrapper2的形参func指向了inner2 

    5、此时走到了f(),即调用f函数,此时f函数已经指向了inner1,最终的执行是 inner1,注意执行的inner1中的func函数指的是 inner2,所以最终执行结果是:

    inner1:before func
    inner2:before func
    f被执行了
    inner2:after func
    inner1:after func

    注意:装饰器的部分就只是各自指来指去,只有到f()才有真实的执行,才有了打印结果,也就是说最终只执行了一个部分:inner1,其中inner1使用了一个 上层局部变量:func,对应func指的是 inner2。三层的装饰器就类比即可,所以只记现象就可以了

    使用场景:比如想要写两个装饰器,1记录用户登录情况,2计算登录函数执行时间,这个时候2一定作为前一个装饰器

    再以上基础上把装饰器的返回值加上,结果返回值用的是 f的哟“hahaha”

    def wrapper1(func):  #func-->innner2
        def inner1():
            print('inner1:before func')
            ret = func()   #f
            print('inner1:after func')
            return ret
        return inner1
    
    def wrapper2(func):  #func-->f
        def inner2():
            print('inner2:before func')
            ret = func()
            print('inner2:after func')
            return ret
        return inner2
    
    @wrapper1
    @wrapper2
    def f():
        print('f被执行了')
        return 'hahahha'
    
    print(f())
    
  • 相关阅读:
    C语言学习11(循环结构:for语句)
    C语言学习9(循环结构:while语句)
    C语言学习8(选择结构的嵌套)
    C语言学习笔记2
    C语言学习笔记1
    C语言的学习5(数据的输出)
    C语言学习12(函数的定义)
    第二十一章流 14临时文件 简单
    第二十一章流 12输出数据到文件指定位置处seekp() 简单
    第二十一章流 11指定读取文件中的数据seekg() 简单
  • 原文地址:https://www.cnblogs.com/txbbkk/p/9410941.html
Copyright © 2020-2023  润新知