您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)Python中Decorator的作用是什么,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
首先來(lái)看一個(gè)簡(jiǎn)單的例子:
# -*- coding: utf-8 -*- def log_cost_time(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 @log_cost_time def complex_func(num): ret = 0 for i in xrange(num): ret += i * i return ret #complex_func = log_cost_time(complex_func) if __name__ == '__main__': print complex_func(100000) code snippet 0
代碼中,函數(shù)log_cost_time就是一個(gè)裝飾器,其作用也很簡(jiǎn)單,打印被裝飾函數(shù)運(yùn)行時(shí)間。
裝飾器的語(yǔ)法如下:
@dec def func():pass
本質(zhì)上等同于: func = dec(func)。
在上面的代碼(code snippet 0)中,把line12注釋掉,然后把line18的注釋去掉,是一樣的效果。另外staticmethod和classmethod是兩個(gè)我們經(jīng)常在代碼中用到的裝飾器,如果對(duì)pyc反編譯,得到的代碼一般也都是 func = staticmthod(func)這種模式。當(dāng)然,@符號(hào)的形式更受歡迎些,至少可以少拼寫(xiě)一次函數(shù)名。
裝飾器是可以嵌套的,如
@dec0 @dec1 def func():pass
等將于 func = dec0(dec1(fun))。
裝飾器也有“副作用“”,對(duì)于被log_cost_time裝飾的complex_calc, 我們查看一下complex_func.__name__,輸出是:”wrapped“”。額,這個(gè)是log_cost_time里面inner function(wrapped)的名字,調(diào)用者當(dāng)然希望輸出是”complex_func”,為了解決這個(gè)問(wèn)題,python提供了兩個(gè)函數(shù)。
functools.update_wrapper
原型: functools.update_wrapper(wrapper, wrapped[, assigned][, updated])
第三個(gè)參數(shù),將wrapped的值直接復(fù)制給wrapper,默認(rèn)為(__doc__, __name__, __module__)
第四個(gè)參數(shù),update,默認(rèn)為(__dict__)
unctools.wraps: update_wrapper的封裝
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.
簡(jiǎn)單改改代碼:
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 \n' % (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ù)用來(lái)指定信息的輸出流,對(duì)于帶參數(shù)的decorator
@dec(dec_args) def func(*args, **kwargs):pass
等價(jià)于 func = dec(dec_args)(*args, **kwargs)。
裝飾器對(duì)類(lèi)的修飾也是很簡(jiǎn)單的,只不過(guò)平時(shí)用得不是很多。舉個(gè)例子,我們需要給修改類(lèi)的__str__方法,代碼很簡(jiǎn)單。
def Haha(clz): clz.__str__ = lambda s: "Haha" return clz @Haha 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é)任
由于裝飾器模式僅從外部改變組件,因此組件無(wú)需對(duì)它的裝飾有任何了解;也就是說(shuō),這些裝飾對(duì)該組件是透明的。
下圖來(lái)自《設(shè)計(jì)模式Java手冊(cè)》或者GOF的《設(shè)計(jì)模式》
回到Python中來(lái),用decorator語(yǔ)法實(shí)現(xiàn)裝飾器模式是很自然的,比如文中的示例代碼,在不改變被裝飾對(duì)象的同時(shí)增加了記錄函數(shù)執(zhí)行時(shí)間的額外功能。當(dāng)然,由于Python語(yǔ)言的靈活性,decorator是可以修改被裝飾的對(duì)象的(比如裝飾類(lèi)的例子)。decorator在python中用途非常廣泛,下面列舉幾個(gè)方面:
(1)修改被裝飾對(duì)象的屬性或者行為
(2)處理被函數(shù)對(duì)象執(zhí)行的上下文,比如設(shè)置環(huán)境變量,加log之類(lèi)
(3)處理重復(fù)的邏輯,比如有N個(gè)函數(shù)都可能跑出異常,但是我們不關(guān)心這些異常,只要不向調(diào)用者傳遞異常就行了,這個(gè)時(shí)候可以寫(xiě)一個(gè)catchall的decorator,作用于所用可能跑出異常的函數(shù)
def catchall(func): @functools.wraps(func) def wrapped(*args, **kwargs): try: return func(*args, **kwargs) except: pass return wrapped
以上就是Python中Decorator的作用是什么,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。