15. 裝飾器

對於某些函式執行之前或之後要加入某些動作或檢查,但是又不修改那些函式的內容(讓動作或檢查可以容易的加入或移除),此時可以用裝飾器(decorator)完成此項工作。

(1) 將輸出的結果改為大寫

以下是一個例子:

def myDecorator(func):
    def wrapper(*args, **kwargs):
        r = func(*args, **kwargs)
        if isinstance(r, str):
            return r.upper()
        else:
            return r
        
    return wrapper
    
@myDecorator    
def myname(name):
    return name

第11行用@myDecorator宣告一個裝飾器來修飾其後的myname函式,此時myname函式的參考將傳給第1行myDecorator的參數func,因此func指向myname函式物件。

第2行的wrapper函式宣告一個包裹myname的函式,在第3行先執行myname函式,取得回傳值後將它轉成大寫(對myname函式增加的動作)。

第9行回傳wrapper的參照並由第12行的myname接收,因此myname就指向了wrapper函式物件。以上完成了在不修改myname內容及參照名稱的情況下,增加了原有myname函式的處理

主程式:

print(myname('tomlin'))

執行結果:

TOMLIN

說明

(2) 使用多個裝飾器

一個函式可以使用多個裝飾器修飾自己,修飾的順序是靠近自己的函式開始,一步步向外套用裝飾器。

以下是一個例子:

#第一個裝飾器
def myDecorator1(func):
    def wrapper(*args, **kwargs):
        r = func(*args, **kwargs)
        if isinstance(r, str):
            return r.upper()
        else:
            return r
        
    return wrapper

#第二個裝飾器
def myDecorator2(func):
    def wrapper(*args, **kwargs):
        r = func(*args, **kwargs)
        return 'abc_' + r + '_xyz'
    
    return wrapper

# 使用裝飾器
@myDecorator1    
@myDecorator2    
def myname(name):
    return name

第22行的myDecorator2先修飾myname,在回傳值前後加入abc__def 文字;接著再套用myDecorator1修飾,將原本文字及新增的文字都轉成大寫

主程式:

print(myname('tomlin'))

執行結果:

ABC_TOMLIN_XYZ

如果改變裝飾順序:

@myDecorator2    
@myDecorator1    
def myname(name):
    return name

執行結果:

abc_TOMLIN_xyz

說明:

(3) 接收參數的裝飾器

以下是一個例子:

#接收參數的裝飾器
def myDecorator(chineseUpper):
    def innerDecorator(func):
        def wrapper(*args, **kwargs):
            up = '零壹貳參肆伍陸柒捌玖'
            lw = '〇一二三四五六七八九'
            r = func(*args, **kwargs)
            
            m = ''
            if chineseUpper:
                for k in str(r):
                    m+=up[int(k)]
            else:
                for k in str(r):
                    m+=lw[int(k)]
            return m        
    
        return wrapper
     
    return innerDecorator

# 使用裝飾器並傳參數
@myDecorator(False)  
def total(price, amount):
    tot = price*amount
    if tot>100000:
        tot*=0.8
        
    return int(tot)

主程式:

print(total(1250, 85))

執行結果:

八五〇〇〇

說明:

問題1:

寫一個新台幣裝飾器,名稱是NTdecorator,負責將被修飾函式計算後的數字轉成國字大寫,如12345轉成壹萬貳仟參百肆拾伍元。假設被修飾函式計算後的數字範圍介於0~1000000之間。

問題2:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

if __name__ == '__main__':
    app.run()

測試以上程式,試著說明第5行指令的意義。

Last updated