This is a convenience function for invoking partial(update_wrapper,wrapped=wrapped,assigned=assigned,updated=updated) as a function decorator when defining a wrapper function.
import functools
def log_cost_time(func):
? ? @functools.wraps(func)
? ? def wrapped(*args, **kwargs):
? ? ? ? import time
? ? ? ? begin = time.time()
? ? ? ? try:
? ? ? ? ? ? return func(*args, **kwargs)
? ? ? ? finally:
? ? ? ? ? ? print 'func %s cost %s' % (func.__name__, time.time() - begin)
? ? return wrapped
再查看complex_func.__name__ 輸出就是 “complex_func”
裝飾器也是可以帶參數(shù)的胸完。
def log_cost_time(stream):
? ? def inner_dec(func):
? ? ? ? def wrapped(*args, **kwargs):
? ? ? ? ? ? import time
? ? ? ? ? ? begin = time.time()
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? return func(*args, **kwargs)
? ? ? ? ? ? finally:
? ? ? ? ? ? ? ? stream.write('func %s cost %s ' % (func.__name__, time.time() - begin))
? ? ? ? return wrapped
? ? return inner_dec
import sys
@log_cost_time(sys.stdout)
def complex_func(num):
? ? ret = 0
? ? for i in xrange(num):
? ? ? ? ret += i * i
? ? return ret
if __name__ == '__main__':
? ? print complex_func(100000)
code snippet 1
log_cost_time函數(shù)也接受一個(gè)參數(shù)呆贿,該參數(shù)用來指定信息的輸出流,對(duì)于帶參數(shù)的decorator
@dec(dec_args)
def func(*args, **kwargs):pass
等價(jià)于 func = dec(dec_args)(*args, **kwargs)蝠筑。
裝飾器對(duì)類的修飾也是很簡(jiǎn)單的皆警,只不過平時(shí)用得不是很多。舉個(gè)例子等浊,我們需要給修改類的__str__方法屯曹,代碼很簡(jiǎn)單瓢喉。
def Haha(clz):
? ? clz.__str__ = lambda s: "Haha"
? ? return clz
class Widget(object):
? ? ''' class Widget '''
if __name__ == '__main__':
? ? w = Widget()
? ? print w
那什么場(chǎng)景下有必要使用decorator呢宁赤,設(shè)計(jì)模式中有一個(gè)模式也叫裝飾器。我們先簡(jiǎn)單回顧一下設(shè)計(jì)模式中的裝飾器模式栓票,簡(jiǎn)單的一句話概述
動(dòng)態(tài)地為某個(gè)對(duì)象增加額外的責(zé)任
由于裝飾器模式僅從外部改變組件决左,因此組件無需對(duì)它的裝飾有任何了解;
回到Python中來走贪,用decorator語法實(shí)現(xiàn)裝飾器模式是很自然的哆窿,比如文中的示例代碼,在不改變被裝飾對(duì)象的同時(shí)增加了記錄函數(shù)執(zhí)行時(shí)間的額外功能厉斟。當(dāng)然挚躯,由于Python語言的靈活性,decorator是可以修改被裝飾的對(duì)象的(比如裝飾類的例子)擦秽。decorator在python中用途非常廣泛码荔,下面列舉幾個(gè)方面:
(1)修改被裝飾對(duì)象的屬性或者行為
(2)處理被函數(shù)對(duì)象執(zhí)行的上下文,比如設(shè)置環(huán)境變量感挥,加log之類
(3)處理重復(fù)的邏輯缩搅,比如有N個(gè)函數(shù)都可能跑出異常,但是我們不關(guān)心這些異常触幼,只要不向調(diào)用者傳遞異常就行了硼瓣,這個(gè)時(shí)候可以寫一個(gè)catchall的decorator,作用于所用可能跑出異常的函數(shù)
def catchall(func):
? ? @functools.wraps(func)
? ? def wrapped(*args, **kwargs):
? ? ? ? try:
? ? ? ? ? ? return func(*args, **kwargs)
? ? ? ? except:
? ? ? ? ? ? pass
? ? return wrapped
(4)框架代碼置谦,如flask堂鲤, bottle等等,讓使用者很方便就能使用框架媒峡,本質(zhì)上也避免了重復(fù)代碼瘟栖。