python中的装饰器和java的注解在外观上很像。python中,装饰器本质上是一个类或一个带有返回类型为函数的高阶函数。
装饰器可以扩展一个类或函数的功能。有关装饰器的详细介绍,推荐查看文章“Python装饰器注解”
下面讲讲python中装饰器的本质,我在bilibili上找到一个讲的很好的一个视频,链接是:
【python】装饰器超详细教学,用尽毕生所学给你解释清楚,以后再也不迷茫了!_哔哩哔哩_bilibili
def dec(f):
pass
@dec
def double(x):
return x *2
#上面double函数上增加注解后,完全等价于下面的写法
double = dec(double)
可以看到,装饰器本质上是一个返回类型为函数的高阶函数。当在一个普通函数上增加注解,则本质上系统会调用装饰器函数dec,参数为函数对象double,然后装饰器函数返回一个函数对象,并赋值给一个跟函数名同名的对象double。
例子1: 下面看一个实际的例子
def timeit(f):
def wrapper(x):
start = time.time()
ret = f(x)
print(time.time() - start)
return ret
return wrapper
@timeit
def my_func(x):
time.sleep(1)
if __name__ == '__main__':
my_func(1)
运行后输出
1.005021095275879
编译器运行到下面代码的时候
@timeit
def my_func(x):
time.sleep(1)
所以其本质是运行了
my_func = timeit(my_func)
所以当调用my_func(1)时,实际上是在执行wrapper(1)。
例子二:注解上还可以增加注解
看看下面的代码运行结果是什么
import time
def timeit(f):
def wrapper(x):
start = time.time()
ret = f(x)
print(time.time() - start)
return ret
return wrapper
@timeit
@timeit
def my_func(x):
time.sleep(1)
if __name__ == '__main__':
my_func(1)
运行后结果为:
1.0050477981567383
1.0051438808441162
编译器运行到下面代码时
@timeit
@timeit
def my_func(x):
time.sleep(1)
实际上执行了my_func=timeit(timeit(my_func))
例子3: 装饰器有参数
看看下面代码
import time
def timeit(k):
def inner(f):
def wrapper(x):
start = time.time()
for _ in range(k):
ret = f(x)
print(time.time() - start)
return ret
return wrapper
return inner
@timeit(2)
def my_func(x):
time.sleep(1)
if __name__ == '__main__':
my_func(1)
其中
@timeit(2)
def my_func(x):
time.sleep(1)
本质上变成了
my_func = timeit(2)(my_func)