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

一、装饰器解释

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

2、符合开放封闭原则

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

3、装饰器用来做什么?

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

4、装饰器怎么定义:

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

def runc():
    pass

res=callable(runc)
print(res)

二、采用闭包形式执行

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、将函数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、@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()

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

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)

传参流程图

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

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

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)

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

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)

八、装饰器装饰类

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)         #<function decorator.<locals>.wrapper at 0x000001E84F9E99D0>

obj=TestDemo()
obj1=TestDemo()
obj2=TestDemo()

print(obj)			#<__main__.TestDemo object at 0x000002826039B0A0>
print(obj1)
print(obj2)

执行逻辑:

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)

@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()

执行逻辑示意图

缺点:

没办法获得装饰器中的参数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()

执行结果:

装饰器拓展前的功能代码age 18
————work————:
装饰器拓展前的功能代码sex aa

物联沃分享整理
物联沃-IOTWORD物联网 » python——装饰器深入研究(一)

发表评论