(转)python里为什么需要使用装饰器(decorator)

Posted goyier

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(转)python里为什么需要使用装饰器(decorator)相关的知识,希望对你有一定的参考价值。

出处

为什么需要使用装饰器呢?其实很多人学习python之后都会问这个问题。
这一次,我来深入地学习一下什么是装饰器,以及为什么需要它。
其实这个装饰器就是我们这样的程序员太“懒”了,基本上什么事情都想少做,追求是DRY,那么什么是DRY,如下:
DRY(Don‘t repeat yourself 
),字面意思来看:"不要重复自己"。强调的意思就是在进行编程时相同的代码不要重复写,最好只写一次,然后可以在其他地方直接引用。如此一来,可以提高代码重用率,缩减代码量,同时也有助于提高代码的可读性和可维护性。当需要做出更改时,只需要更改一个地方即可。


有了这个指导思想,就很明白了,就是少写代码,装饰器的目的也就是少写代码,复用代码。
复用代码有很多种方式,比如面向对象里的继承,虚函数等,但是想在函数层面来复用代码,有什么方法呢?
一般情况之下,就是函数中调用另一个函数来达到继承和复用。函数里调用别的函数,如下面的例子:

1 #python 3.6
2 def add():
3     return 1 + 1
4  
5 def sub():
6     return 2 -1
7  
8 print(add())
9 print(sub())

 

输出如下:

2
1

如果这时,我们想把每个函数添加一行星号打印输出,以便分隔开来,更好看一些,我们往往会这样做修改,
每个函数里添加一行星号就行了,修改如下:

 1     #python 3.6
 2     def add():
 3         print(*************************************)
 4         return 1 + 1
 5      
 6     def sub():
 7         print(*************************************)
 8         return 2 -1
 9      
10     print(add())
11     print(sub())

 

 

输出如下:

*************************************
2
*************************************
1

当我们只有两个函数时,这样修改很快的,并且很快就完成工作了,但是如果有1000个这样函数呢?那么是否需要添加1000遍?
如果你每个函数去添加一个也是可以完成任务的,但是有想法,或者更聪明的办法,就不是这样了。能否不修改原来的函数,即是原来的函数代码一点都不改变,又能增加这样的功能呢?答案是可以的,如下修改:

 1     #python 3.6
 2     def add():
 3     return 1 + 1
 4      
 5     def sub():
 6     return 2 -1
 7      
 8     #定义一个新的函数
 9     def printStar(func):
10     print(*************************************)
11     return func()
12      
13     print(printStar(add))
14     print(printStar(sub))

 

输出如下:
*************************************
2
*************************************
1
在这里增加了一个函数,这个函数接收一个函数对象作为参数,这样就不需要修改原来的函数,达到原来稳定并且测试通过的代码不作任何修改,减少出错的风险,特别已经上线运行的系统,更是如此;或者像8代单传的代码,没有人敢去修改它,否则领导会怪你,怎么样把产品越改越差,本来是请你来做好产品的,结果不行。做到这一步,就结束了吗?还不行啊,因为每个调用这个函数的地方都需要修改,因此再继续修改,结果改成这样:

 1     #python 3.6
 2     #定义一个新的函数
 3     def printStar(func):
 4     print(*************************************)
 5     return func()
 6      
 7     @printStar
 8     def add():
 9     return 1 + 1
10      
11     def sub():
12     return 2 -1
13      
14      
15      
16     print(add)
17     print(printStar(sub))

 

输出结果如下:

*************************************
2
*************************************
1

这里发现调用add方法,还是不一样,继续修改,代码如下:

 1     #python 3.6
 2     #定义一个新的函数
 3     def printStar(func):
 4     def f():
 5     print(*************************************)
 6     return func()
 7     return f
 8      
 9     @printStar
10     def add():
11     return 1 + 1
12      
13     def sub():
14     return 2 -1
15      
16     print(add())
17      
18     sub = printStar(sub)
19     print(sub())

 

输出结果如下:

*************************************
2
*************************************
1

到这里,可以发现使用嵌套函数来实现,就可以返回一个可调用的对象,这样更加完美了。

 1     #python 3.6
 2     #定义一个新的函数
 3     def printStar(func):
 4     def f():
 5     print(*************************************)
 6     return func()
 7     return f
 8      
 9     @printStar
10     def add():
11     return 1 + 1
12      
13     @printStar
14     def sub():
15     return 2 -1
16      
17     print(add())
18      
19     print(sub())

 

在这里可以发现这两段代码是相等的:

def sub():    
    return 2 -1

sub = printStar(sub) 

@printStar
def sub():    
    return 2 -1

由此可见@printStar是一个语法改变,它的目标就是实现不修改原来函数的代码,又可以复用原来的函数并且作出修改,也称作为元编程,并且装饰器函数可以复用,实现共享的目标。

以上是关于(转)python里为什么需要使用装饰器(decorator)的主要内容,如果未能解决你的问题,请参考以下文章

python 装饰器

Python全栈day28(类的装饰器)

python装饰器(备忘)

关于装饰器迭代器生成器以及其它一些内容的整理

Python进阶-----类的装饰器及应用

飘逸的python - 装饰器的本质