Python的裝飾器是個(gè)好東西,它能干很多事情羽莺。但對(duì)于新手,它看起來(lái)似乎沒(méi)那么簡(jiǎn)單洞豁。
但事實(shí)上盐固,裝飾器本身也只是個(gè)函數(shù)荒给。
import time
def log(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print("The func '{}' used {}s.".format(func.__name__, end-start))
return result
return warpper
這一個(gè)裝飾器,當(dāng)我們這樣使用時(shí)
@log
def fuck(name):
"""Fuck someone"""
print("Fuck", name)
它只是執(zhí)行了fuck = log(fuck)
這樣一句代碼而已刁卜。
也就是說(shuō)志电,我們表面上是用fuck("myself")
,事實(shí)上執(zhí)行的都是log(fuck)("myself")
蛔趴。因?yàn)镻ython里面都是對(duì)象嘛挑辆。
同樣的道理,假設(shè)我們定義了一個(gè)帶參數(shù)的裝飾器logging
孝情,它實(shí)際上執(zhí)行的是
func = logging(arguments)(func)
也就是上面那個(gè)不帶參數(shù)的裝飾器多定義一層就行了鱼蝉。
import time
def logging(arguments):
def log(func):
def warpper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print("The func '{}' used {}s.".format(func.__name__, end-start))
return result
return warpper
# do something
return log
但,當(dāng)我們使用一個(gè)裝飾器之后箫荡,它會(huì)將原本的函數(shù)元信息給覆蓋掉魁亦。譬如:函數(shù)名稱,函數(shù)文檔等等羔挡。
例如上例
print(fuck.__name__)
print(fuck.__doc__)
你會(huì)發(fā)現(xiàn)吉挣,函數(shù)信息全部沒(méi)了!fuck
它不叫fuck
婉弹,改名叫wrapper
了睬魂。它的文檔也變成了none
。
解決辦法很簡(jiǎn)單镀赌,定義裝飾器的時(shí)候用warps
裝飾器裝飾接受原函數(shù)參數(shù)的那一層就行了氯哮。
這個(gè)來(lái)自functools模塊的裝飾器能幫你復(fù)制函數(shù)的元信息到被綁定的函數(shù)身上。
修改裝飾器如下(其實(shí)就加了一行代碼hhh)
import time
from functools import wraps
def log(func):
@wraps(func)
def warpper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print("The func '{}' used {}s.".format(func.__name__, end-start))
return result
return warpper
當(dāng)我們?cè)龠\(yùn)行
print(fuck.__name__)
print(fuck.__doc__)
就能看到函數(shù)的的元信息沒(méi)變了商佛。
- 裝飾器定義時(shí)加
@wraps
是個(gè)好習(xí)慣喉钢。
一個(gè)較為實(shí)用的裝飾器demo在該專題的另一篇文章:函數(shù)參數(shù)類型檢查