上次講了
Python
的閉包效诅,今天來講一下閉包的應用——裝飾器
1. 裝飾器是什么
什么叫裝飾器?顧名思義离陶,它是一個用來裝飾的東西。用來裝飾誰呢衅檀?用來裝飾函數(shù)招刨。由于裝飾器器自身也是一個函數(shù),所以哀军,一句話來說沉眶,裝飾器是一個用來裝飾函數(shù)的函數(shù)。感覺有點拗口杉适,那么沦寂,在我的理解,裝飾器只是個輔助函數(shù)淘衙,有沒有它并不影響被裝飾函數(shù)的運行传藏。下面聽我娓娓道來。
2.函數(shù)的表達
在講之前彤守,我們先來看一下函數(shù)毯侦,有這樣一個函數(shù):
def func():
print "running func"
我們都知道,運行func()
將會輸出:
>> running func
然而具垫,運行func
侈离,則輸出:
>> <function func at 0x7f70236215f0>
所以我們看到在函數(shù)名之后加了括號會進入函數(shù)內(nèi)部運行,而不加括號只是代表了一個函數(shù)對象(Python
中一切皆對象筝蚕,函數(shù)也是)卦碾,記住這點可以幫我們更好的理解裝飾器。
3.場景
現(xiàn)在我有一堆函數(shù)例如:
def func1():
print "running func1"
def func2():
print "running func2"
def func3():
print "running func3"
不過現(xiàn)在起宽,為了證明這些函數(shù)是我寫的洲胖,都要打印一句話。那么坯沪,我可能會這樣寫:
def func1():
print "running func1"
print "強哥好帥绿映!"
其他函數(shù)也是如此。然而,到以后函數(shù)多了的時候叉弦,你會感覺這樣寫很是麻煩丐一,而且還更改了原函數(shù)的業(yè)務邏輯,非常不好淹冰。這時候库车,便可以用閉包來實現(xiàn)。
4.用閉包簡化
改成閉包的形式如下:
#把此函數(shù)寫在最上面樱拴,因為`Python`解釋器自上而下解釋
def shoe_me(func):
def wrapper():
print "強哥好帥柠衍!"
func()
return wrapper
#原函數(shù)
def func1():
print "running func1"
func1 = show_me(func1)
if __name__ == '__main__':
func1()
運行后的結果如圖:
注意:當程序運行到
func1 = show_me(func1)
時并沒有立即執(zhí)行函數(shù),只是定義了一個新函數(shù)疹鳄。show_me(func1)
其實等價于如下:
def wrapper():
print "強哥好帥拧略!"
func1()
所以芦岂,只有當func1()
時瘪弓,才真正運行。這正好對應了第二部分中函數(shù)執(zhí)行的原理禽最。
5.用裝飾器進一步簡化
以上需求的實現(xiàn)還是有一點繁瑣腺怯,Python
大發(fā)給我們提供了@
語法糖,來看一下怎么使用:
@shoe_me
def func2():
print "running func2"
運行程序func2()
,輸出如下圖:
如程序所示川无,
@shoe_me
和原來閉包實現(xiàn)func2 = show_me(func2)
是完全等價的呛占,這樣便能在不改變原函數(shù)的情況下添加裝飾,增加功能懦趋。
顯然晾虑,上面的例子除了裝B,確實沒有其他功能仅叫。那裝飾器到底有什么實際功能呢帜篇?如函數(shù)日志分析(對上面的裝飾器改進),登陸訪問(Django
中的@login_required
)诫咱,權限驗證笙隙,緩存設置,記數(shù)器等坎缭,下一節(jié)將繼續(xù)介紹裝飾器的高級用法竟痰。
6.后記
略啰嗦,最后一部分才引入裝飾器掏呼。坏快。。