1. 程式人生 > >(轉)python裏為什麽需要使用裝飾器(decorator)

(轉)python裏為什麽需要使用裝飾器(decorator)

上線 深入 add 指導 對象 引用 是否 寫代碼 學習

出處

為什麽需要使用裝飾器呢?其實很多人學習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)