裝飾器是一種用於封裝函數或類的代碼工具。它顯式的將封裝器應用到函數或類上,從而使它們選擇加入到裝飾器的功能中。閉包
裝飾器究其本質是一個接受可調用函數的可調用函數,並返回一個可調用函數。裝飾器是一個函數,該函數接受被裝飾的函數做爲其位置參數,裝飾器經過使用該參數來執行某些操做,而後返回原始參數或一些其餘的調用。模塊化
看下面的代碼,是一個簡單的裝飾器:函數
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__屬性。工具
將被裝飾函數應用裝飾器通常寫做:spa
1 @decorated_by 2 def add(x, y): 3 return x + y
裝飾器實現的原理是什麼呢?裝飾器之因此可以實現是因爲Python的閉包。調試
再來看一段代碼:code
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變量。簡單的說,這種內部函數可使用外部函數變量的行爲,叫作閉包。
再來看一段代碼:blog
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閉包的一種應用。class
使用裝飾器的好處在於:一、使代碼能夠複用。從上邊的代碼能夠看出,裝飾器的主要做用是對參數進行檢驗,所以該裝飾器能夠用於全部有相似參數檢驗需求的函數,避免了大量冗餘代碼;二、因爲裝飾器是顯式的,它們在全部須要它們的被調用函數中使用。所以這對於可讀性頗有價值,從而使調試也更加方便。當一個裝飾器編寫的足夠好時,它們是模塊化且清晰明確的。