装饰器的是一种AOP切面编程思想,可以将核心代码从冗长的业务代码中剥离出来,常见的打日志例子:
def log():
import inspect
print(f‘called by {inspect.stack()[1][3]}...‘)
def add():
log()
print(‘add...‘)
def multiplication():
log()
print(‘multiplication...‘)
if __name__ == ‘__main__‘:
multiplication()
add()
called by multiplication...
multiplication...
called by add...
add...
这里log()为了举例并不复杂,但是如果业务更复杂,可能会将核心代码add() multiplication()“淹没”且会重复写某些代码。而这就是出发点,孕育出了装饰器的思想。装饰器,从字面意思也可意会到其涉及想法,起到一个装饰的作用,而被装饰者必然是核心业务代码
针对上面的例子,我们配合装饰器修改一下:
def wapper(fun):
def log(): # 返回该方法, 该方法中包含 fun()——核心逻辑代码
import inspect
print(f‘called by {fun.__name__}...‘)
fun()
return log
def add():
print(‘add...‘)
def multiplication():
print(‘multiplication...‘)
if __name__ == ‘__main__‘:
add = wapper(add) # 返回被 wapper 包装过的 add 方法. 取成 add 的名字罢了
mul = wapper(multiplication)
add()
mul()
called by add...
add...
called by multiplication...
multiplication...
那么同样的,如果需要带参数,也只要简单的修改一下:
def wapper(fun):
def log(*args, **kwargs):
import inspect
print(f‘called by {fun.__name__}...‘)
fun(*args, **kwargs) # 根据传入的参数按个数前后顺序匹配 add(a,b,l) 参数
return log
def add(a, b, l):
print(f‘add...{a+b}‘)
for i in l:
print(i)
if __name__ == ‘__main__‘:
add = wapper(add)
add(4,7, [9,99]) # 调用wapper中的log函数
called by add...
add...11
9
99
照上个例子再套一层,其实没有什么意义,就是方便更加充分理解(●ˇ?ˇ●):
关于闭包nonlocal,可点击查看nonlocal, 查看闭包
def wapper(msg):
def inner_wapper(fun):
nonlocal msg # 闭包
msg += 1
print(msg)
def log(*args, **kwargs):
import inspect
print(f‘called by {fun.__name__}...‘)
fun(*args, **kwargs)
return log
return inner_wapper
def add(a, b, l):
print(f‘add...{a+b}‘)
for i in l:
print(i)
10
called by add...
add...11
9
99
了解了上文的几个例子,为了写的简便一些可以使用 @ ——只是为了写的更方便,其实我还是喜欢上文的更简单直观
@wapper(9) # 添加装饰器
def add(a, b, l):
print(f‘add...{a+b}‘)
for i in l:
print(i)
if __name__ == ‘__main__‘:
add(4,7, [9,99])
类装饰器其实和上文的装饰器没有多大区别。如果A是一个函数对象,A()调用函数,如果是一个类对象A()自然调用__call__()方法。所以如下例子:
class wapper:
def __init__(self, fun, msg):
self.msg = msg
self.fun = fun
print(self.msg)
def __call__(self, *args, **kwargs):
msg, = args
print(msg)
def log(*args, **kwargs):
print(f‘called by {self.fun.__name__}...‘)
return self.fun(*args, **kwargs)
return log
def add(a, b, l):
print(f‘add...{a+b}‘)
for i in l:
print(i)
if __name__ == ‘__main__‘:
add = wapper(add, ‘hi here1‘)(‘__call__ 调用中‘)
print(‘=======‘)
add(4,7, [9,99])
hi here1
__call__ 调用中
=======
called by add...
add...11
9
99
这种形式只需要注意,如果类装饰器本身不需要传入参数,如下 @wapper。执行过程:当调用main中的add方法时,先初始化wapper,可以看到打印了function的名字add,随后add(4,7, [9,99]) 其实执行__call__方法:
class wapper:
def __init__(self, fun):
self.fun = fun
print(self.fun.__name__)
def __call__(self, *args, **kwargs):
print(‘hi here2‘)
print(f‘called by {self.fun.__name__}...‘)
return self.fun(*args, **kwargs)
@wapper
def add(a, b, l):
print(f‘add...{a+b}‘)
for i in l:
print(i)
if __name__ == ‘__main__‘:
add(4,7, [9,99])
add
hi here2
called by add...
add...11
9
99
另一种情况是,当wapper本身传入参数初始化:@wapper(...)初始化wapper, call__传入fun
这种情况可能看上去有点绕,如下:@wapper(‘hi here1‘)初始化,随后add(4,7,[9,99])先调用__call
class wapper:
def __init__(self, msg):
self.msg = msg
print(self.msg)
def __call__(self, fun):
print(‘hi here2‘)
def log(*args, **kwargs):
print(f‘called by {fun.__name__}...‘)
return fun(*args, **kwargs)
return log
@wapper(‘hi here1‘) # 传参数
def add(a, b, l):
print(f‘add...{a+b}‘)
for i in l:
print(i)
if __name__ == ‘__main__‘:
add(4,7, [9,99])
hi here1
hi here2
called by add...
add...11
9
99
https://www.cnblogs.com/cicaday/p/python-decorator.html
原文:https://www.cnblogs.com/KongHuZi/p/13696504.html