Python裝飾器探究——裝飾器參數(shù)

探究裝飾器參數(shù)<a id="sec-1" name="sec-1"></a>

編寫傳參的裝飾器<a id="sec-1-1" name="sec-1-1"></a>

通常我們見到的簡單裝飾器這樣的:

import json
import functools

def json_output(func):
    @functools.wraps(decorated)
    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        return json.dumps(result)
    return inner

@json_output
def f():
    return {'status': 'done'}

當(dāng)裝飾器應(yīng)用于函數(shù) f 上時,它接受 f 作為其參數(shù),返回一個函數(shù) inner ,且將他綁定到變量f上。

示例中我們編寫的裝飾器 json_output 只接受一個隱式參數(shù)——即被裝飾的方法,在使用此裝飾器時本身看上去是并沒有參數(shù)的。然而有時候需要讓裝飾器自身帶有一些需要的信息,從而使裝飾器可以使用恰當(dāng)?shù)姆绞窖b飾方法。比如上面的例子中,我們想通過向裝飾器傳入不同的參數(shù)來控制輸出結(jié)果的縮進(indent)和排序(sort)。我們可以這么做:

import json
import functools

def json_output(indent=None, sort_keys=False):
    def actual_decorator(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            result = func(*args, **kwargs)
            return json.dumps(result, indent=indent, sort_keys=sort_keys)
        return inner
    return actual_decorator

@json_output(indent=4)
def f():
    return {'status': 'done'}

理解傳參的裝飾器<a id="sec-1-2" name="sec-1-2"></a>

初次看起來會覺得比較繞人,因為函數(shù)里嵌套了兩個函數(shù)定義,然而實際上和之前一個版本的區(qū)別在于為了接收json序列化的參數(shù)多包裝了一層,所以

@json_output(indent=4)
def f():
    return {'status': 'done'}

# 相當(dāng)于
@actual_decorator
def f():
    return {'status': 'done'}

這樣看起來就會明晰很多。

實際上, 裝飾器里的 @ 后接收一個函數(shù),該函數(shù)以被裝飾的函數(shù)(例子中是f)為參數(shù),并且返回一個函數(shù)。當(dāng)需要在裝飾函數(shù)的同時傳入?yún)?shù)的話,那么就需要多包裝一層,先傳入?yún)?shù)(例子中是 indent=4 )返回一個裝飾的函數(shù)(例子中是 actual_decorator ), 這個返回的的函數(shù) 就跟以前一樣接受被裝飾的函數(shù)(f)作為參數(shù)并且返回一個函數(shù)作為裝飾最后的方法供調(diào)用。

傳參和不傳參的兼容<a id="sec-1-3" name="sec-1-3"></a>

然而當(dāng)我們像上面那樣定義裝飾器時,就不能這樣調(diào)用:

import json
import functools

def json_output(indent=None, sort_keys=False):
    def actual_decorator(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            result = func(*args, **kwargs)
            return json.dumps(result, indent=indent, sort_keys=sort_keys)
        return inner
    return actual_decorator

@json_output
def f():
    return {'status': 'done'}

在實際的項目過程中,有時會出現(xiàn)這樣的狀況: 一開始寫的裝飾器時不需要使用時傳參數(shù)的,后來發(fā)現(xiàn)有必要傳參數(shù),改好后原來不傳參的裝飾器不能正常使用了,這是修改原來使用的地方是項痛苦的事情。
這時候就需要對裝飾器做一個兼容,使它在以下情況都可用:

@json_output
@json_output()
@json_output(indent=4)

具體做法如下:

import json
import functools

def json_output(decorated_=None, indent=None, sort_keys=False):
    if decorated_ and (indent or sort_keys):
        raise

    def actual_decorator(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            result = func(*args, **kwargs)
            return json.dumps(result, indent=indent, sort_keys=sort_keys)
        return inner
    if decorated_:
        return actual_decorator(decorated_)
    else:
        return actual_decorator


@json_output(indent=4)
def f1():
    return {'status': 'done'}

@json_output
def f2():
    return {'status': 'done'}

@json_output()
def f3():
    return {'status': 'done'}

print f1()
print f2()
print f3()

代碼中關(guān)鍵的地方在于 json_output 在最后對參數(shù) decorated 進行了判斷,有的話證明是不傳參調(diào)用,那么直接返回 actual_decorator 的調(diào)用;沒有的話則代表是傳參類型的調(diào)用(雖然參數(shù)可能不存在),那么返回 actual_decorator 。其中有點需要注意, josn_output 的傳參需要使用關(guān)鍵字參數(shù),如果像下面這樣直接傳一個位置參數(shù),那么根據(jù)現(xiàn)在的實現(xiàn)會出現(xiàn)錯誤(因為它會被當(dāng)成 decorated_ )。

@json_output(4)  #錯誤的使用方法
def f4():
    return {'status': 'done'}

參考資料<a id="sec-2" name="sec-2"></a>

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

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

  • 要點: 函數(shù)式編程:注意不是“函數(shù)編程”,多了一個“式” 模塊:如何使用模塊 面向?qū)ο缶幊蹋好嫦驅(qū)ο蟮母拍?、屬性?..
    victorsungo閱讀 1,697評論 0 6
  • 本文為《爬著學(xué)Python》系列第四篇文章。從本篇開始,本專欄在順序更新的基礎(chǔ)上,會有不規(guī)則的更新。 在Pytho...
    SyPy閱讀 2,573評論 4 11
  • 每個人都有的內(nèi)褲主要功能是用來遮羞,但是到了冬天它沒法為我們防風(fēng)御寒,咋辦?我們想到的一個辦法就是把內(nèi)褲改造一下,...
    chen_000閱讀 1,403評論 0 3
  • Python進階框架 希望大家喜歡,點贊哦首先感謝廖雪峰老師對于該課程的講解 一、函數(shù)式編程 1.1 函數(shù)式編程簡...
    Gaolex閱讀 5,991評論 6 53
  • 圖·文/大萌 在生活中經(jīng)常會聽有人說,哪些整天曬照片的人就是裝逼,有什么了不起的,照...
    牛友果星球大萌閱讀 3,225評論 109 141

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