一、装饰器解释
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