由于函數(shù)也是一個(gè)對(duì)象,而且函數(shù)對(duì)象可以被賦值給變量,所以,通過變量也能調(diào)用該函數(shù)。
def now():
print '2013-12-25'
f = now
f()
#打印結(jié)果
2013-12-25
函數(shù)對(duì)象有一個(gè)name屬性,可以拿到函數(shù)的名字:
print now.__name__
print f.__name__
#打印結(jié)果
now
now
現(xiàn)在,假設(shè)我們要增強(qiáng)now()函數(shù)的功能,比如,在函數(shù)調(diào)用前后自動(dòng)打印日志,但又不希望修改now()函數(shù)的定義,這種在代碼運(yùn)行期間動(dòng)態(tài)增加功能的方式,稱之為“裝飾器”(decorator)
本質(zhì)上,decorator就是一個(gè)返回函數(shù)的高階函數(shù),所以,我們要定義一個(gè)能打印日志的decorator,可以定義如下:
def log(func):
def wrapper(*args,**kw):
print 'call %s():' %func.__name__
return func(*args,**kw)
return wrapper
觀察上面的log(),因?yàn)樗且粋€(gè)decorator,所以接受一個(gè)函數(shù)作為參數(shù),并返回一個(gè)函數(shù)。我們要借助Python的@語(yǔ)法,把decorator置于函數(shù)的定義處:
@log
def now():
print '2013-12-25'
now()
#調(diào)用now()函數(shù),不僅會(huì)運(yùn)行now()函數(shù)本身,還會(huì)在運(yùn)行now()函數(shù)前打印一行日志,運(yùn)行結(jié)果:
call now():
2013-12-25
把@log放到now()函數(shù)的定義處,相當(dāng)于執(zhí)行了:
now = log(now)
由于,log()是一個(gè)decorator,返回一個(gè)函數(shù),所以,原來(lái)的now()函數(shù)仍然存在,只是現(xiàn)在同名的now變量變量指向了新的函數(shù),于是調(diào)用now()將執(zhí)行新函數(shù),即在log()函數(shù)中返回wrapper()函數(shù)。
wrapper函數(shù)的參數(shù)定義是(args,*kw),因此,wrapper()函數(shù)可以接受任意參數(shù)的調(diào)用。在wrapper()函數(shù)內(nèi),首先打印日志,再緊接著調(diào)用原始函數(shù)。
如果decorator本身需要傳入?yún)?shù),那就需要編寫一個(gè)需要返回decorator的高階函數(shù),寫出來(lái)更復(fù)雜,比如,要自定義log的文本: