装饰器,在官网文档上的解释很简单粗暴。所以让人感觉难以理解。
我这里给一个定义。解释不官方,是我的理解。
装饰器实现一种功能,然后这种功能作用在被调用的函数上,可以避免在不同的函数上编写相同的内容。
是不是感觉和函数调用函数有点类似?因为本质上装饰器就是这么一个操作。
装饰器是语法糖,也就是不增加功能,只是提供了另一种写法。
某人说过。世上本没有装饰器,只是提的需求多了,才有了装饰器。
我们就看看,一个简单的功能,在什么样的要求下,才一步一步变成装饰器的。
既然叫装饰器,我们就用“装饰”函数的案例讲解。
比如我们有两个函数,分别计算输入项目相加的和、以及相乘的积。
什么样子的需求才会让这么一个简单的项目逐渐改变到需要使用装饰器的呢?
def add_func(*args): #计算和 return sum(args) def mul_func(*args): #计算积 result = 1 for i in args: result*=i return result # 使用方式 add_func(1,5,6,9) mul_func(1,5,6,9)
问题:我们发现函数会计算结果,但是如果不使用print(),除了交互式运行,你不知道结果是什么。
那么,你就想着既要print,又要return结果。你就可能会将函数改成下面的情况。
修改函数,增加输出“正在计算”、“计算结果”等字样。
def add_func(*args): print("正在计算") print("计算的结果是",sum(args)) return sum(args) def mul_func(*args): print("正在计算") result = 1 for i in args: result*=i print("计算的结果是",result) return result add_func(1,5,6,9) mul_func(1,5,6,9)
问题:如果我们的函数很多,就需要修改很多地方,那么我们就可能将相同部分放到一个函数中。
实现的时候,就用函数调用函数去实现。
我们这里定义了一个decorator_func函数,我们成为“装饰函数”。之前的函数,成为“业务函数”。
def decorator_func(func,*args): #用于装饰的函数 print("正在计算") print("计算的结果是",func(*args)) #func(*args)调用业务函数 def add_func(*args): #业务函数1,计算和 return sum(args) def mul_func(*args): #业务函数2,计算积 result = 1 for i in args: result*=i return result # 使用方式 decorator_func(add_func,1,5,6,9) #用decorator_func调用add_func函数 decorator_func(mul_func,1,5,6,9) #用decorator_func调用mul_func函数
问题:虽然即装饰了函数,又解决了业务函数过多,而需要大量修改的情况。但是我们仍不满意。
decorator_func()既然是一个装饰函数而不是业务函数,我们更关心的是业务函数。
decorator_func(add_func,1,5,6,9)这种实现形式,我们还需要反复提到,decorator_func()。我们想要的就是add_func(1,5,6,9)就实现之前所有的需求。
第三步中的需求,我们很快想要增加下面的内容。
add_func = decorator_func(add_func) mul_func = decorator_func(mul_func)
add_func 覆盖掉原本的函数代码,变成装饰函数调用业务函数的代码。
但是为了让参数对应,我们需要修改装饰函数。def decorator_func(func,*args)改成def decorator_func(func)。但是*args的内容又不能丢掉。
所以,你经常看到装饰函数有一个内部函数 inner(),它的作用,是为了承接多余的参数。
修改:
def decorator_func(func): def inner(*args): #定义内部函数inner,让它去承接多余的参数。 print("正在计算") result = func(*args) print("计算的结果是",result) return result return inner #业务函数部分不变。 def add_func(*args): return sum(args) def mul_func(*args): result = 1 for i in args: result*=i return result #让业务函数名指向 装饰函数调用业务函数。 add_func = decorator_func(add_func) mul_func = decorator_func(mul_func) #使用方式 add_func(1,5,6,9) mul_func(1,5,6,9)
实际上,这里我们已经完成所有内容了。
在不修改业务函数的情况下,add_func(1,5,6,9)调用形式也没有变,就实现了对它的输出结果进行“装饰”的效果。
问题:装饰器写法怎么写呢?
这里是最简单的,如图。
是不是很简单?
看到这里,你应该已经理解官方文档上,那句很简单粗暴的总结。
正因为文档上没有讲解装饰器从何演变而来,所以才对我们的理解造成了影响。
装饰器:就是指明用什么函数去装饰某个函数。本质上就是函数调用函数。
只不过我们调用的时候,可以直接使用原本的函数名,而不需要使用装饰函数名。
有了这么一个理解,再去看别人装饰器在类和函数中的例子,就容易理解了。