装饰器
demo:
@func1
def func():
print("aaa")
装饰器存在的意义
- 不影响原有函数的功能
- 可以添加新功能
一般常见的,比如拿到第三方的API接口,不允许修改这个接口.这个时候,装饰器就派上了用场
装饰器本身也是一个函数,作用是为现有存在的函数,在不改变函数的基础上,增加一些功能进行装饰
它是以闭包的形式去实现的
在使用装饰器函数时,在被装饰的函数前一行,使用@装饰器函数名
形式来进行装饰
Demo:
现在在一个项目中,有许多函数,由于我们的项目越来越大,功能也越来越多,导致程序越来越慢
其中一个功能函数的功能,实现一百万次的累加
def my_count():
s = 0
for i in range(1000001):
s += i
print('sum:', s)
假如我们要计算运行的时间
import time
def my_count():
s = 0
for i in range(1000001):
s += i
print('sum:', s)
start = time.time()
my_count()
end =time.time()
print('执行时间:', (end-start))
虽然成功计算了运行时间,但是,大量函数计算时非常麻烦,代码量凭空增加很多
明显不符合开发原则,代码太过冗余
def count_time(func):
start = time.time()
func()
end = time.time()
print('执行时间:', (end-start))
count_time(my_count)
经过修改,定义一个函数来实现时间计算功能
初看上去,比之前好很多
只是在使用时,需要将对应的函数传入到时间计算函数中
仍然影响了原来的使用
接下来思考,能不能在使用时不影响函数的原来使用方式,同时实现时间计算?
考虑闭包
import time
def count_time(func):
def wrapper():
start = time.time()
func()
end = time.time()
print('执行时间:', (end-start))
return wrapper
def my_count():
s = 0
for i in range(1000001):
s += i
print('sum:', s)
print(count_time(my_count)())# 仍然更改了调用方式
在使用时,让my_count函数重新指向count_time函数返回的函数引用。这样使用my_count时,就和原来的一样了。
import time
def count_time(func):
def wrapper():
start = time.time()
func()
end = time.time()
print('执行时间:', (end-start))
return wrapper
@count_time
def my_count():
s = 0
for i in range(1000001):
s += i
print('sum:', s)
my_count()
这样实现的好处,定义闭包函数后,只需要通过@装饰器函数名
形式的装饰器语法,就可以将@装饰器函数名
加到要装饰的函数前即可。
这种不改变原有函数功能,对函数进行拓展的形式,就称为装饰器
在执行@装饰器函数名
时,就是将原函数传递到闭包中。然后,原函数的引用指向闭包返回的装饰过的内部函数的引用。