Python装饰器
装饰器是一种用于封装函数或类的代码工具。它显式的将封装器应用到函数或类上,从而使它们选择加入到装饰器的功能中。
装饰器究其本质是一个接受可调用函数的可调用函数,并返回一个可调用函数。装饰器是一个函数,该函数接受被装饰的函数作为其位置参数,装饰器通过使用该参数来执行某些操作,然后返回原始参数或一些其他的调用。
看下面的代码,是一个简单的装饰器:
1 def decorated_by(func): 2 func.__doc__ += '\nDecorated by decorated_by.' 3 return func 4 5 def add(x, y): 6 return x + y 7 8 add = decorated_by(add)
在上面这段代码中,decorated_by是装饰器,add是被装饰的函数,代码的作用就是修改了add函数的__doc__属性。
将被装饰函数应用装饰器一般写作:
1 @decorated_by 2 def add(x, y): 3 return x + y
装饰器实现的原理是什么呢?装饰器之所以能够实现是由于Python的闭包。
再来看一段代码:
def func(a, b): x=a y=b def add(): z=4 return x+y+z return add >>>add = func(1, 2) >>>add() 7
add是func的内部函数,在add的局部作用域中可以直接访问func局部作用域中定义的x, y变量。简单的说,这种内部函数可以使用外部函数变量的行为,叫做闭包。
再来看一段代码:
1 def dec(func): 2 def in_dec(*arg): 3 if len(arg) == 0: 4 return 0 5 for val in arg: 6 if not isinstance(val, int): 7 return 0 8 return func(*arg) 9 return in_dec 10 11 @dec 12 def my_sum(*arg): 13 return sum(arg) 14 15 @dec 16 def my_average(*arg): 17 return sum(arg) / len(arg) 18 19 print (my_sum(1,2,3,4,5,6)) (等同于mysum = dec(my_sum); mysum(1,2,3,4,5,6)) 20 print (my_average(1,2,3,4,5,6))
我们来分析一下整个的调用过程:
首先当遇到语法糖@dec时,调用dec,然后它会返回in_dec,由于my_sum作为一个参数传入dec,因此它作为闭包内的变量被in_dec所使用,这时my_sum被重新赋值my_sum = in_dec,所以我们调用my_sum时其实是调用了in_dec,而in_dec有调用了原来的my_sum。以上就是装饰器所做的事情,其实就是Python闭包的一种应用。
使用装饰器的好处在于:1、使代码可以复用。从上边的代码可以看出,装饰器的主要作用是对参数进行检验,因此该装饰器可以用于所有有类似参数检验需求的函数,避免了大量冗余代码;2、由于装饰器是显式的,它们在所有需要它们的被调用函数中使用。因此这对于可读性很有价值,从而使调试也更加方便。当一个装饰器编写的足够好时,它们是模块化且清晰明确的。