• python——装饰器深入研究(一)


    在这里插入图片描述

    一、装饰器解释

    1、装饰器属于设计模式的一种:装饰器模式

    2、符合开放封闭原则

    开放:对拓展开放
    封闭:对修改封闭

    3、装饰器用来做什么?

    可以在不修改功能函数内部代码的情况下,给功能函数进行拓展新的功能

    4、装饰器怎么定义:

    1、闭包实现
    2、类实现
    3、普通函数
    只要是可调用的对象(加括号就能调用),都可以作为装饰器,通过callable内置函数进行判断

    def runc():
        pass
    
    res=callable(runc)
    print(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二、采用闭包形式执行

    def fun_work(func):
    
        def fun_test(*args,**kwargs):
            print('开始执行')
            if args[1]==0:
                print('b不能为0')
            else:
                func(*args,**kwargs)
            print('结束执行')
        return fun_test
    
    def work(a, b):
        res = a / b
        print('a除B的结果为:', res)
    
    work=fun_work(work)(10,2)       #todo 执行函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    执行逻辑:

    1、将函数work作为参数传递到fun_work函数中,返回fun_test
    2、把fun_test返回值用所传参数同名的变量work去接收
    3、调用work(),执行fun_test(*args,**kwargs)方法

    在这里插入图片描述

    三、采用装饰器执行

    def fun_work1(func):
    
        def fun_test1(*args,**kwargs):
            print('开始执行')
            if args[1]==0:
                print('b不能为0')
            else:
                func(*args,**kwargs)
            print('结束执行')
        return fun_test1
    
    @fun_work1
    def work(a, b):
        res = a / b
        print('a除B的结果为:', res)
    
    work(10,2)  #todo 执行函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行逻辑:

    1、@fun_work1 :表示调用装饰器fun_work1函数
    2、把被装饰器装饰的函数work传递到fun_work1中
    3、并且把返回的结果(fun_test1)传给与函数同名的变量work
    4、@fun_work1这行代码相当于work=fun_work1(work)
    5、调用work()===执行fun_test1()

    在这里插入图片描述

    四、闭包实现最简单装饰器的框架

    def outer(func):    #func用来接收被装饰器装饰的函数名称
    
        def inner():
            #函数执行前的功能拓展代码
            func()
            #函数执行后的功能拓展代码
    
        return inner
    
    @outer
    def work():
        pass
    
    work()			#执行work():也就是执行inner()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    五、装饰器装饰带有参数的函数

    def outer(func):
    
        def inner(a,b):
            print('a-b的值为:',a - b)
            func(a,b)
            print('a*b的值为:', a * b)
        return inner
    
    
    @outer
    def work(a,b):
        print('a+b的值为:',a + b)
    
    work(10,10)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    传参流程图

    在这里插入图片描述

    六、装饰器如何做到通用,可以装饰参数个数多个的函数?

    通用装饰器的写法,一定要会

    def outer(func):
    
        def inner(*args,**kwargs):
    
            #函数执行前的功能拓展代码
            res=func(*args,**kwargs)
    		#函数执行后的功能拓展代码
            return res
        
        return inner
    
    
    @outer
    def work(a,b,c):
        return 'a+b+c的值为:{}'.format(a+b+c)
    
    res=work(10,10,10)
    print(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    七、被装饰器装饰的函数有返回值,怎么解决?

    def outer(func):
    
        def inner(a,b):
            print('a-b的值为:',a-b)
            res=func(a,b)
            print('a*b的值为:', a * b)
            return res
        return inner
    
    
    @outer
    def work(a,b):
        return 'a+b的值为:{}'.format(a+b)
    
    res=work(10,10)
    print(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    八、装饰器装饰类

    def decorator(item):            #item接收TestDemo
    
        def wrapper(*args,**kwargs):
    
            #功能拓展
            print('{}实例化了一个对象'.format(item))
            result=item(*args,**kwargs)
            #功能拓展
    
            return result
    
        return wrapper
    
    
    @decorator      #TestDemo=decorator(TestDemo)
    class TestDemo:
        pass
    
    print(TestDemo)         #.wrapper at 0x000001E84F9E99D0>
    
    obj=TestDemo()
    obj1=TestDemo()
    obj2=TestDemo()
    
    print(obj)			#<__main__.TestDemo object at 0x000002826039B0A0>
    print(obj1)
    print(obj2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    执行逻辑:

    1、@decorator:将类TestDemo作为参数传递给装饰器decorator中————————》decorator(TestDemo)
    2、并且将decorator(TestDemo)用和传递给装饰器同名的参数TestDemo作为变量——————》TestDemo=decorator(TestDemo)
    3、TestDemo():调用TestDemo相当于调用wrapper方法
    4、result=item(*args,**kwargs)——————》item表示TestDemo类,初始化一个item对象,result是对象名称
    5、调用TestDemo()——————》调用wrapper方法返回result——————》需要接收返回值:obj=TestDemo(),obj就是实例化的对象

    九、带参数的装饰器

    案例1:用pytest做自动化测试时用到装饰器

    @pytest.mark.parametrize('item',[11,22,33,44])
    def test_demo(item):
        print("item",item)
    
    • 1
    • 2
    • 3

    @pytest.mark.parametrize('item',[11,22,33,44])的执行逻辑:
    先调用函数,将整体的返回值作为装饰器,装饰test_demo函数

    @pytest.mark.parametrize('item',[11,22,33,44])
    等于
    result=pytest.mark.parametrize('item',[11,22,33,44])
    @result
    执行语句:test_demo=result(test_demo)

    案例2:实现带参数的装饰器

    def outer(func):
    
        def inner(*args,**kwargs):
    
            res=func(*args,**kwargs)
    
            return res
    
        return inner
    
    
    def kobe(age,sex):
        return outer			#必须返回装饰器函数名称
    
    @kobe(18,'aa')
    def work():
        print("------------work------------:")
    
    
    work()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    执行逻辑示意图

    在这里插入图片描述

    缺点:

    没办法获得装饰器中的参数age,sex

    案例3:实现带参数的装饰器最终版(模板)

    最外层的参数,是装饰器的参数
    中间层的参数:接收被装饰的函数
    最里层的参数:接收的是被装饰器装饰的函数调用时传递的参数

    @kobe(18,‘aa’)等同于work=kobe(18,‘aa’)(work)

    def kobe(age,sex):
        #todo 最外层的参数,是装饰器的参数
        def outer(func):
            #todo 中间层的参数:接收被装饰的函数
            def inner(*args, **kwargs):
                #todo 最里层的参数:接收的是被装饰器函数调用时传递的参数
                print('装饰器拓展前的功能代码age',age)
                res = func(*args, **kwargs)
                print('装饰器拓展前的功能代码sex', sex)
    
                return res
    
            return inner
        return outer
    
    @kobe(18,'aa')
    def work():
        print("------------work------------:")
    
    
    work()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    执行结果:

    装饰器拓展前的功能代码age 18
    ------------work------------:
    装饰器拓展前的功能代码sex aa
    在这里插入图片描述

  • 相关阅读:
    经典蓝牙Inquiry过程的跳频
    创建Struts2项目并实现一个例子
    回馈负载的工作原理
    【21天python打卡】第9天 基础技能(2)
    【设计模式】单例模式
    PAT甲级打卡-1005-1010
    Vue3中自定义事件实现子组件向父组件传递数据
    第43节——redux介绍
    webpack常用配置与性能优化插件
    HRD特征及其检测方法简介
  • 原文地址:https://blog.csdn.net/YZL40514131/article/details/126671683