python裝飾器

python的裝飾器一直是Python里不太好理解的一部分,但是使用確是非常頻繁的一個東西。用好裝飾器可以讓代碼更加簡潔,更具可讀性,所以這里分享一下我對python裝飾器的理解。

python裝飾器個功效有點類似于java的web開發(fā)中spring面向切面編程的前置后置增強,可以在我們的目標操作前先執(zhí)行一些預處理。經(jīng)常用在輸出日志,性能測試或者事物處理的地方。

如何編寫一個裝飾器

現(xiàn)在來做一個日志增強的功能:


def log(func): 
def wrapper(*args, **kwargs):
    print 'call %s()' % func.__name__
    return func(*args, **kwargs)
return wrapper


@log
def hello():
    print 'hello'

if __name__ == '__main__':
    hello()

output:

call hello()
hello

這里新建了一個函數(shù)叫l(wèi)og接收一個函數(shù)做為參數(shù)內(nèi)部有一個函數(shù)叫做wrapper的功能就是打印一句日志。當我們調(diào)用hello()的時候不僅hello本身會執(zhí)行還會執(zhí)行l(wèi)og里面的打印語句。其實我們在def hello前面加上的@log的作用相當于hello = log(hello)而@符號只是python給它的一個語法糖而已,看起來更簡潔美觀。

functools @wraps

由于我們的裝飾器其實相當于調(diào)用hello=log(hello)而log是返回wrapper函數(shù)的,所以如果這時候我們打印hello.__name__會發(fā)現(xiàn)輸出是wrapper這樣我們的函數(shù)名字都變了。如果你對函數(shù)名又要求或者用到函數(shù)的一些屬性,這樣就會造成一些不可預測的后果。于是python在2.5版本之后的functools模塊中加入了一個裝飾器叫做@wraps

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print 'call %s()' % func.__name__
        return func(*args, **kwargs)
    return wrapper

@log
def hello():
    print 'hello'

if __name__ == '__main__':
    print hello.__name__

這里我們在wrapper上面加入了一個這個裝飾器再打印hello的名字的適合就不是wrapper而是hello了,其實@functools.wraps(func)就是把wrapper函數(shù)的各個屬性更新為我們想要裝飾的函數(shù)的屬性。

為裝飾器添加參數(shù)

經(jīng)常我們在一些web框架里可以看到很多裝飾器用來路由web頁面的url同時也加入了很多參數(shù)。比如flask里面:

@app.route('/logout')
def logout():
    session.pop('logged_in', None)
    flash('You were logged out')
    return redirect(url_for('show_entries'))

這里使用了@app.route這個裝飾器并且傳入了一個參數(shù),那么怎么編寫一個可以傳入?yún)?shù)的裝飾器呢?

下面我們寫一個可以接收一個參數(shù)的裝飾器:

def assign_info(text): 
    def decorater(func):
        @functools.wraps(func)
        def wrapper():
            print 'info:' + text
            return func()
        return wrapper
    return decorater

@ assign_info('decorater input')
def hello():
    print 'hello---'

if __name__ == '__main__':
    hello()

可以看到我們這個裝飾器變成了三層第一次是可以接收我們的參數(shù)的函數(shù),里面是裝飾器函數(shù),最里面是wrapper函數(shù),然后再一層一層的返回。剛剛說到我們寫的那個log裝飾器相當于調(diào)用hello=log(hello),那現(xiàn)在我們的三層的又是怎么調(diào)用的呢?其實這相當于hello=assign_info('decorater input')(hello)

總結(jié):python的裝飾器在很多地方都經(jīng)常用到,所以理解并掌握它非常必要,學會了裝飾器可以讓代碼變得更簡潔,開發(fā)效率也可以得到顯著提高,在很多比如權(quán)限管理,日志管理等地方我們都可以做成裝飾器來處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容

  • 一.函數(shù)裝飾器 1.從Python內(nèi)層函數(shù)說起 首先我們來探討一下這篇文章所講的內(nèi)容Inner Functions...
    軟體動物Ai閱讀 3,271評論 0 14
  • 雖然人們能利用函數(shù)閉包(function clouser)寫出簡單的裝飾器,但其可用范圍常受限制。多數(shù)實現(xiàn)裝飾器的...
    gomibako閱讀 1,033評論 0 4
  • 每個人都有的內(nèi)褲主要功能是用來遮羞,但是到了冬天它沒法為我們防風御寒,咋辦?我們想到的一個辦法就是把內(nèi)褲改造一下,...
    chen_000閱讀 1,373評論 0 3
  • 有時候我們想為多個函數(shù),同意添加某一種功能,比如及時統(tǒng)計,記錄日志,緩存運算結(jié)果等等,而又不想改變函數(shù)代碼那就定義...
    ketchup閱讀 3,074評論 0 3
  • 海水退潮后,大量的魚被擱淺在海灘上。一個小男孩見狀,開始拾起魚一條一條地往海里扔。一個路過的人不理解:“這么多魚,...
    紅雲(yún)說口才閱讀 172評論 0 0