Python裝飾器

什么是裝飾器?

類似于Java的注解。在python中叫做裝飾器,目的是用于對(duì)已存在代碼進(jìn)行修改。這里的修改是狹義的,并非任意的修改,而是能夠?qū)ζ鋱?zhí)行過(guò)程進(jìn)行編譯時(shí)修改。

最簡(jiǎn)單示例

def DecoratorTest(fun):
    def _T_fun_(id):
        print("before call -----")
        fun(id)
        print("after call -----")
    return _T_fun_

@DecoratorTest
def OutputX(id):
    print(id)

OutputX(20)

輸出結(jié)果:

before call -----
20
after call -----

在沒(méi)有使用裝飾器之前,輸出20,使用裝飾器之后,實(shí)現(xiàn)了對(duì)OutputX函數(shù)的邏輯修改,這個(gè)就是裝飾器的作用。

有什么用?

雖然前一個(gè)章節(jié)中,大致說(shuō)明了裝飾器的用法,但很多人還是不會(huì)用,原因在于不知道到底這個(gè)功能應(yīng)該應(yīng)用于什么場(chǎng)景。如果螺絲刀只是被描述為一頭是一字形或十字形的器具,可能即使遇到一個(gè)螺絲,都不會(huì)想到螺絲刀,所以將工具與場(chǎng)景緊密關(guān)聯(lián)是很重要的。裝飾器常用的就兩個(gè)場(chǎng)景:

  1. 構(gòu)建流程注入,例如注入日志、性能分析處理;
  2. 程序擴(kuò)展實(shí)現(xiàn),適合在處理流程中添加具體擴(kuò)展實(shí)現(xiàn),實(shí)現(xiàn)類似回調(diào)功能;

怎么用?

流程注入

假設(shè)一個(gè)場(chǎng)景:設(shè)計(jì)了一個(gè)系統(tǒng),希望在某個(gè)場(chǎng)景下可以記錄系統(tǒng)內(nèi)函數(shù)的執(zhí)行過(guò)程信息,幫助進(jìn)行問(wèn)題定位,實(shí)現(xiàn)類似日志的功能。
簡(jiǎn)化原系統(tǒng)實(shí)現(xiàn)如下:

def FunA(a):
  return a+20
def FunB(a, b):
  return a+b
def FunC(a, b):
  return FunA(a)+FunB(a, b)

print(FunC(30,40))

輸出結(jié)果為:

120

這時(shí),發(fā)現(xiàn)輸出數(shù)字與預(yù)期不相符,怎么辦?除了調(diào)試,如果希望通過(guò)日志來(lái)定位解決問(wèn)題,那么修改系統(tǒng)實(shí)現(xiàn)如下:

def AFun(fun):
    def CallBack(*args, **args2):
        print("befor call "+getattr(fun,"__name__"))
        ret = fun(*args, **args2)
        if ret is not None:
            print("Return:")
            print(ret)
        print("befor call "+getattr(fun,"__name__"))
        return ret
    return CallBack
        
@AFun
def FunA(a):
  return a+20
@AFun
def FunB(a, b):
  return a+b
@AFun
def FunC(a, b):
  return FunA(a)+FunB(a, b)

print(FunC(30,40))

最終輸出如下:

befor call FunC
befor call FunA
Return:
50
befor call FunA
befor call FunB
Return:
70
befor call FunB
Return:
120
befor call FunC
120

通過(guò)這種方式,在不修改原代碼邏輯的基礎(chǔ)上,添加了日志執(zhí)行輸出功能,還可以對(duì)調(diào)用過(guò)程進(jìn)行時(shí)間統(tǒng)計(jì),分析系統(tǒng)的性能瓶頸。

擴(kuò)展實(shí)現(xiàn)

假設(shè)場(chǎng)景:假設(shè)設(shè)計(jì)一個(gè)web框架,最起碼一個(gè)需求就是用戶可以擴(kuò)展定義響應(yīng)鏈接,例如響應(yīng)“/a/b"的"get"請(qǐng)求。有兩種設(shè)計(jì)方式,先看正常常規(guī)設(shè)計(jì)方式:

url_processors = {}
def WebEngine(url, method):
    if url in url_processors and method in url_processors[url]:
        return url_processors[url][method]()
    else:
        return 404

def ProcessA():
    print("in process A")
    return "Hello A"

url_processors["/A"] = {}
url_processors["/A"]["get"] = ProcessA

print(WebEngine("/A", "get"))
print(WebEngine("/B", "get"))

執(zhí)行輸出結(jié)果如下:

in process A
Hello A
404

從上邊看到,修改響應(yīng)信息,需要維護(hù)兩個(gè)地方的代碼,容易帶來(lái)不一致問(wèn)題,也提升了維護(hù)成本。利用裝飾器如何解決這個(gè)問(wèn)題,代碼示例如下:

url_processors = {}
def WebEngine(url, method):
    global url_processors
    if url in url_processors and method in url_processors[url]:
        return url_processors[url][method]()
    else:
        return 404

def DeclMethod( url="", method=""):
    def DSF(fun):
        global url_processors
        
        url_processors[url] = {}
        url_processors[url][method] = fun
    return DSF


@DeclMethod(url="/A", method="get")
def ProcessA():
    print("in process A")
    return "Hello A"

print(WebEngine("/A", "get"))
print(WebEngine("/B", "get"))

從代碼上看,擴(kuò)展一個(gè)響應(yīng),只需要在函數(shù)前添加具體的擴(kuò)展裝飾聲明即可。執(zhí)行結(jié)果如下:

in process A
Hello A
404

總結(jié)

在學(xué)習(xí)過(guò)程中,需要將工具與場(chǎng)景進(jìn)行聯(lián)系,在場(chǎng)景的解決實(shí)踐中,會(huì)發(fā)現(xiàn)很多其他不足,例如在上例中,涉及了不定長(zhǎng)參數(shù)的處理,裝飾器參數(shù)的處理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文轉(zhuǎn)自http://mingxinglai.com/cn/2015/08/python-decorator/ [...
    Jlan閱讀 620評(píng)論 0 5
  • 裝飾器是程序開(kāi)發(fā)中經(jīng)常會(huì)用到的一個(gè)功能,功能就是在運(yùn)行原來(lái)功能基礎(chǔ)上,加上一些其它功能,比如權(quán)限的驗(yàn)證,比如日志的...
    壁花燒年閱讀 334評(píng)論 0 0
  • 在python編程中,我們經(jīng)??吹较旅娴暮瘮?shù)用法: with open("test.txt", "w") as f...
    hugoren閱讀 920評(píng)論 0 0
  • 一 裝飾器介紹 1.1 為何要用裝飾器 軟件的設(shè)計(jì)應(yīng)該遵循開(kāi)放封閉原則,即對(duì)擴(kuò)展是開(kāi)放的,而對(duì)修改是封閉的。對(duì)擴(kuò)展...
    100斤的瘦子_湯勇閱讀 624評(píng)論 0 0
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來(lái)的情緒。表情可以傳達(dá)很多信息。高興了當(dāng)然就笑了,難過(guò)就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 129,466評(píng)論 2 7

友情鏈接更多精彩內(nèi)容