背景:
不想改变函数的调用方式但是想在原函数前后添加功能
通过闭包实现(初级实现装饰器):
下面f1()是被装饰的函数,f2()是装饰器函数
def f1():
print('this is f1')
def f2(f):
print('this is f2')
def inner():
print('this is inner')
f()
return inner
f1 = f2(f1)
f1() # f1原功能输出 this is f1不变,在f1前面输出this is f2 和 this is inner
'''
this is f2
this is inner
this is f1
'''
开放封闭原则:
开放:对扩展是开放的
封闭:对修改是封闭的
语法糖:
使代码更便捷 ’@‘
先调用@修饰的函数再调用被修饰函数
被修饰的函数的返回值无法正常接收,需要在装饰器函数里获取被装饰函数的返回值再返回
上面的例子使用语法糖后:
def f2(f):
print('this is f2')
def inner():
print('this is inner')
f()
return inner
@f2
def f1():
print('this is f1')
return 'f1 return'
f1()
'''
this is f2
this is inner
this is f1
'''
res = f1()
print(res) # None
================================
# 获取被装饰函数的返回值
def f2(f):
print('this is f2')
def inner():
print('this is inner')
res = f()
return res
return inner
@f2
def f1():
return ('this is f1')
print(f1())
'''
this is f2
this is inner
this is f1
'''
动态传参的装饰器:
def f1(f):
def inner(*args, **kwargs):
print('this is inner')
res = f(*args, **kwargs)
return res
return inner
@f1
def f2(a, b):
return [a, b]
@f1
def f3(a, b, name='test'):
return [a, b, {'name':name}]
res2 = f2(1, 2)
print(res2) # this is inner [1, 2]
res3 = f3(1, 2, 'xinian')
print(res3) # this is inner [1, 2, {'name': 'xinian'}]
装饰器固定模式:
def wrapper(func):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
@wrapper
def test(a, b):
return a + b
res = test(1, 2)
print(res) # 3
多个装饰器:
def wrapper1(f): # f = inner2
def inner1():
print('inner1 before f')
f()
print('inner1 after f')
return inner1
def wrapper2(f): # f = test
def inner2():
print('inner2 before f')
f()
print('inner2 after f')
return inner2
@wrapper1 # 然后关联第二个,此时wrapper1的入参f是前面wrapper2返回的inner2,返回inner1
@wrapper2 # 先关联最近的,此时wrapper2的入参f = test,返回inner2
def test():
print('this is test')
'''
下面调用时相当于调用inner1,
先输出inner1 before f
然后调用inner1里面的f(),此时f = inner2
因此输出inner2 before f
然后inner2里面的f(),此时f = test
因此执行真正的test,输出this is test
然后输出inner2 after f,执行完inner2回到调用点inner1
输出inner1 after f
'''
test()
'''
先执行wrapper1在调用test前的代码,
再执行wrapper2在调用test前的代码,
再执行test,
再执行wrapper2在调用test后的代码,
再执行wrapper1在调用test后的代码,
inner1 before f
inner2 before f
this is test
inner2 after f
inner1 after f
'''