一、什么是装饰器
装饰器就类似于你自己有好多衣服,换一套衣服就是新的样貌,但你始终是你,没有变。装饰器运用在函数中的话可以拓展你的代码,不需要你修改原来的函数和函数调用。装饰器分为函数装饰器和类装饰器。
二、为什么要用装饰器
先了解python中的函数也可作为函数的参数,如下:
def yisu():
print("我是伊苏尔德")
def erde(name):
print('进入erde函数')
name()
print('我叫伊苏尔德root,感谢大家关注我')
if __name__ == '__main__':
func = yisu
func()
print('------------')
erde(yisu)
那么我现在想知道他们的执行时间,修改代码如下:
import time
def yisu():
t = time.time()
print("我是伊苏尔德")
time.sleep(3)
print("执行时间:", time.time() - t)
def erde(name):
t = time.time()
print('进入erde函数')
name()
print('我叫伊苏尔德root,感谢大家关注我')
print("执行时间:", time.time() - t)
if __name__ == '__main__':
func = yisu
func()
print('------------')
erde(yisu)
此时我有一个新的函数,也想去计算执行时间,但是又会重复上面的代码,我们需要更方便一点,因此需要装饰器,让我们拓展一些原来函数没有的功能。
三、简单装饰器
import time
def yisu():
print("我是伊苏尔德")
time.sleep(2)
def count_time(func):
def wrapper():
t= time.time()
func()
print("执行时间为:", time.time() - t)
return wrapper
if __name__ == '__main__':
yisu = count_time(yisu)
yisu()
count_time是一个装饰器,装饰器函数里面定义一个wrapper函数,把func函数当作参数传入,并返回wrapper函数。wrapper函数体就是要实现装饰器的内容。
四,装饰器的语法糖@
装饰器默认传入的参数就是被装饰的函数,加@就可以省略yisu = count_time(yisu)
import time
def count_time(func):
def wrapper():
t = time.time()
func()
print("执行时间为:", time.time() - t)
return wrapper
@count_time
def yisu():
print("我是伊苏尔德")
time.sleep(2)
if __name__ == '__main__':
yisu()
五、装饰器传参
当我们被装饰的函数带参数时,就需要升级我们的装饰器了,将我们的装饰器改成如下,可以接受任何参数。
import time
def count_time(func):
def wrapper(*args, **kwargs):
t = time.time()
func(*args, **kwargs)
print("执行时间为:", time.time() - t)
return wrapper
@count_time
def erde(name):
print('进入erde函数')
name()
print('我叫伊苏尔德root,感谢大家关注我')
@count_time
def yisu():
print("我是伊苏尔德")
time.sleep(2)
if __name__ == '__main__':
erde(yisu)
六、带参装饰器
装饰器函数也可以是函数,那么怎么写一个带参装饰器呢?如下:
import time
def count_time_args(msg=None):
def count_time(func):
def wrapper(*args, **kwargs):
t = time.time()
func(*args, **kwargs)
print(f"[{msg}]执行时间为:", time.time() - t)
return wrapper
return count_time
@count_time_args(msg="yisu")
def fun():
time.sleep(1)
if __name__ == '__main__':
fun()
基于原来的count_time函数外部再包一层用于接收参数的count_time_args,接收回来的参数就可以直接在内部的函数里面调用了
七、类装饰器
就像函数装饰器一样,同类的类也可以有装饰器。当我们将类作为一个装饰器时,通过__init__()方法初始化类,通过__call__()方法调用真正的装饰方法。
import time
class YisuDecorator:
def __init__(self, func):
self.func = func
print("执行类的__init__方法")
def __call__(self, *args, **kwargs):
print('进入__call__函数')
t = time.time()
self.func(*args, **kwargs)
print("执行时间为:", time.time() - t)
@YisuDecorator
def yisu():
print("我是伊苏尔德")
time.sleep(2)
def python_erde_list():
time.sleep(3)
print("+++++++++++")
@YisuDecorator
def erde(name):
print('进入erde函数')
name()
print('我是伊苏尔德')
if __name__ == '__main__':
yisu()
print('--------------')
erde(python_erde_list)
当装饰器有参数的时候,__init__() 函数就不能传入func(func代表要装饰的函数)了,而func是在__call__函数调用的时候传入的。