装饰器
装饰器来自 Decorator
的直译。什么叫装饰,就是装点、提供一些额外的功能。在 python 中的装饰器则是提供了一些额外的功能。
装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
装饰器用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
一.一个装饰器的写法
def mylog(func):
def innfunc(*args,**kwargs):
print('日志记录...,start')
func(*args,**kwargs)
print('日志记录...,end')
return innfunc
@mylog
def func1():
print('功能1')
@mylog
def func2(a,b,c):
print('功能2',a,b,c)
func1()
func2(100,200,300)
二.多个装饰器的写法
#多个装饰器
#在函数定义阶段:执行顺序是从最靠近函数的装饰器开始,自内而外的执行
#在函数执行阶段:执行顺序由外而内,一层层执行
import time
def mylog(func):
print('mylog,start!')
def innfunc():
print('日志记录,start')
func()
print('日志记录,end')
print('mylog,end!')
return innfunc
def cost_time(func):
print('cost_time,start!')
def innfunc():
print('开始计时')
start = time.time()
func()
end = time.time()
print(f'总共耗时:{end-start}')
print('cost_time,end!')
return innfunc
@mylog
@cost_time #先执行cost_time→mylog的外在函数,然后先执行mylog→cost_time的内部函数
def func2():
print('func2')
time.sleep(3)
func2()
三.带参数的装饰器典型写法
#带参数的装饰器的典型写法
def mylog(type):
def decorator(func):
def innfunc(*args,**kwargs):
if type == '文件':
print('文件中:日志记录....')
else:
print('控制台:日志记录....')
return func(*args,**kwargs)
return innfunc
return decorator
@mylog('文件')
def func2(a,b):
print('func2',a,b)
if __name__ == '__main__':
func2(100,200)
四.类装饰器的写法
#类装饰器
class MylogDecorator():
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
print('日志记录...')
return self.func(*args, **kwargs)
@MylogDecorator
def func2():
print('func2')
if __name__ == '__main__':
func2()
综合练习
缓存和计时装饰器的综合练习
# 缓存和计时装饰器的综合练习
import time
class CacheDecorator():
__cache={}
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
# 如果缓存中有对应的方法名,则直接返回对应的返回值
if self.func.__name__ in CacheDecorator.__cache:
return CacheDecorator.__cache[self.func.__name__]
# 如果缓存中没有对应的方法名,则进行计算,并将结果缓存
else:
result = self.func(*args,**kwargs)
CacheDecorator.__cache[self.func.__name__] = result
return result
def cost_time(func):
def infunc(*args,**kwargs):
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print(f"耗时:{end-start}")
return result
return infunc
@cost_time
@CacheDecorator
def func1_long_time():
"""模拟耗时较长,每次执行返回结果都一样的情况"""
print("start func1")
time.sleep(3)
print("end func1")
return 999
if __name__ == '__main__':
r1 = func1_long_time()
r2 = func1_long_time()
print(r1)
print(r2)