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、由于装饰器是显式的,它们在所有需要它们的被调用函数中使用。因此这对于可读性很有价值,从而使调试也更加方便。当一个装饰器编写的足够好时,它们是模块化且清晰明确的。

 

posted @ 2017-11-13 17:15  阿基米德的鸭子  阅读(177)  评论(0编辑  收藏  举报