寫(xiě)在前面
首先理解下,python的裝飾器@mydec
是一個(gè)語(yǔ)法糖,它的本質(zhì)是func = mydec(func)
,也就是說(shuō)把函數(shù)func
作為參數(shù)傳入在mydec
中。
引子
假設(shè)一個(gè)函數(shù)要打印用戶(hù)的姓名、年齡、性別當(dāng)然還有其他Blablabla…
def print_human_information(name, age, sex):
print("name is {}, age is {}, sex is {}.".format(name, age, sex))
if __name__ == "__main__":
print_human_information(name="Lee", age=-10, sex='unknown')
然后突然你想看下這個(gè)函數(shù)執(zhí)行花了多少時(shí)間,可能你會(huì)這么寫(xiě):
import time
def print_human_information(name, age, sex):
start = time.clock()
print("name is {}, age is {}, sex is {}.".format(name, age, sex))
end = time.clock()
print "execute in {:.2f} ms".format((end - start) * 1000)
if __name__ == "__main__":
print_human_information(name="Lee", age=-10, sex='unknown')
增加一個(gè)start,一個(gè)end,完美!
但是,如果再有一個(gè)函數(shù)不打印human,打印animal呢?Ctrl+C、V?太low逼!我們有更好的辦法解決這個(gè)問(wèn)題。
import time
def timeused(function):
def wrapper(name, age, sex):
start = time.clock()
function(name, age, sex)
end = time.clock()
print "execute in {:.2f} ms".format((end - start) * 1000)
return wrapper
def print_human_information(name, age, sex):
print("name is {}, age is {}, sex is {}.".format(name, age, sex))
# 看這里,看這里,看這里
# 重要的事情說(shuō)三遍
print_human_information = timeused(print_human_information)
if __name__ == "__main__":
print_human_information(name="Lee", age=-10, sex='unknown')
現(xiàn)在只要有了print_human_information = timeused(print_human_information)
在main
函數(shù)中不需要做任何修改就可以顯示函數(shù)執(zhí)行的時(shí)間,接著讓我們?cè)賮?lái)一個(gè)更簡(jiǎn)潔的語(yǔ)法。
@timeused
def print_human_information(name, age, sex):
…
完美!
進(jìn)階
現(xiàn)在打印animal的函數(shù)真的來(lái)了,然而參數(shù)個(gè)數(shù)只有兩個(gè):
@timeused
def print_animal_information(name, age):
print("name is {}, age is {}.".format(name, age))
好吧,timeused報(bào)錯(cuò)了,修改內(nèi)嵌函數(shù)以及function的參數(shù)形式如下,支持任意多個(gè)參數(shù):
def timeused(function):
def wrapper(*args, **kwargs):
start = time.clock()
function(*args, **kwargs)
end = time.clock()
print "execute in {:.2f} ms".format((end - start) * 1000)
return wrapper
God祥曾經(jīng)教導(dǎo)我們:
一旦滿(mǎn)足了某個(gè)需求,那么接下來(lái)類(lèi)似的需求就會(huì)接踵而至。
很快,我們需要一個(gè)裝飾器來(lái)檢查print_human_information
或print_animal_information
中age
和sex
的合法性。(如年齡不能為負(fù)數(shù),人類(lèi)性別只能是male
或者female
,而對(duì)于動(dòng)物我們不關(guān)心,因此該項(xiàng)不檢查)
或許,現(xiàn)在是時(shí)候編寫(xiě)一個(gè)包含參數(shù)的裝飾器了!
# 默認(rèn)不檢查年齡和性別
def check(check_age = False, check_sex = False):
def wrapper(function):
def _wrapper(*args, **kwargs):
if check_age:
_age = kwargs['age']
if _age < 0 or _age > 140:
print "invalid age '{}', use default {}.".format(_age, 0)
kwargs['age'] = 0
if check_sex:
_sex = kwargs['sex']
if _sex != 'male' or _sex != 'female':
print "invalid sex '{}', use default {}.".format(_sex, 'male')
kwargs['sex'] = 'male'
function(*args, **kwargs)
# 用于展示裝飾器嵌套的效果
time.sleep(0.5)
return _wrapper
return wrapper
@check(check_age = True, check_sex = True)
@timeused
def print_human_information(name, age, sex):
…
@timeused
@check(check_age = True)
def print_animal_information(name, age):
…
資料
Python裝飾器學(xué)習(xí)(九步入門(mén))
PEP 0318 -- Decorators for Functions and Methods
PythonDecoratorLibrary