Python裝飾器探究——裝飾器引數

發表於2016-12-19

編寫傳參的裝飾器

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

當裝飾器應用於函式 f 上時,它接受 f 作為其引數,返回一個函式 inner ,且將他繫結到變數f上。

示例中我們編寫的裝飾器 json_output 只接受一個隱式引數——即被裝飾的方法,在使用此裝飾器時本身看上去是並沒有引數的。然而有時候需要讓裝飾器自身帶有一些需要的資訊,從而使裝飾器可以使用恰當的方式裝飾方法。比如上面的例子中,我們想通過向裝飾器傳入不同的引數來控制輸出結果的縮排(indent)和排序(sort)。我們可以這麼做:

理解傳參的裝飾器

初次看起來會覺得比較繞人,因為函式裡巢狀了兩個函式定義,然而實際上和之前一個版本的區別在於為了接收json序列化的引數多包裝了一層,所以

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

實際上, 裝飾器裡的 @ 後接收一個函式,該函式以被裝飾的函式(例子中是f)為引數,並且返回一個函式。當需要在裝飾函式的同時傳入引數的話,那麼就需要多包裝一層,先傳入引數(例子中是 indent=4 )返回一個裝飾的函式(例子中是 actual_decorator ), 這個返回的的函式 就跟以前一樣接受被裝飾的函式(f)作為引數並且返回一個函式作為裝飾最後的方法供呼叫。

傳參和不傳參的相容

然而當我們像上面那樣定義裝飾器時,就不能這樣呼叫:

在實際的專案過程中,有時會出現這樣的狀況: 一開始寫的裝飾器時不需要使用時傳引數的,後來發現有必要傳引數,改好後原來不傳參的裝飾器不能正常使用了,這是修改原來使用的地方是項痛苦的事情。
這時候就需要對裝飾器做一個相容,使它在以下情況都可用:

具體做法如下:

程式碼中關鍵的地方在於 json_output 在最後對引數 decorated 進行了判斷,有的話證明是不傳參呼叫,那麼直接返回 actual_decorator 的呼叫;沒有的話則代表是傳參型別的呼叫(雖然引數可能不存在),那麼返回 actual_decorator 。其中有點需要注意, josn_output 的傳參需要使用關鍵字引數,如果像下面這樣直接傳一個位置引數,那麼根據現在的實現會出現錯誤(因為它會被當成 decorated_ )。

參考資料

  • 《Python高階程式設計》 by Luke Sneeriger

相關文章