13.Python 裝飾器 (Decorator)
日期:2024/04/11
13.Python 裝飾器 (Decorator)
當談到 Python 的裝飾器(Decorator)時,它們是一種強大的工具,可以在不改變函式本身的情況下,動態地擴展函式的功能。想像你有一個函式,你想要在不更改它的程式碼的情況下,將某些功能添加到它上面。這就是裝飾器的用武之地。
13.1 介紹
裝飾器本身就是函式,但是它接受另一個函式作為參數,然後返回一個新的函式,或者修改傳遞給它的函式,以添加額外的功能。這聽起來有點抽象,但是讓我們看一個簡單的例子來幫助理解。
假設你有一個函式 addNumbers(),它只是簡單地相加兩個數值:
def addNumbers(a, b):print(a + b)
現在,你想要在每次呼叫 addNumbers() 時,都在打印消息之前和之後加上一些其他的動作,比如時間戳記。你可以通過創建一個裝飾器來實現這一點:
import datetimedef addTimestamp(func):def wrapper(a, b):print(datetime.datetime.now())func(a, b)print(datetime.datetime.now())return wrapper@addTimestampdef addNumbers(a, b):print(a + b)addNumbers(3, 5)
好吧!如果還是不清楚我們逐步來說明。
13.2 Python 函式就是物件
在 11.Python 類別 (Class)章節時有提到呼叫函式時可以不先加上()並且設定一個參數給他。
def addNumbers(a, b):print(a + b)addTwo = addNumbersaddTwo(3, 5)
當然也可以在函式裡再定義另一個函式。
def addNumbers(a, b):def getAnswer():return 'A: 'result = getAnswer() + str(a + b)return resultprint(addNumbers(3, 5))# A: 8
甚至函式可以當做參數傳給另一個函式
def getAnswer(num):return 'A: ' + str(num)def callFunc(func):num = 3 + 5return func(num)print(callFunc(getAnswer))# A: 8
函式可以回傳函式
def callFunc():def addNumbers():return 3 + 5return addNumbersresult = callFunc()print(result())# 8
最後再說一個觀念內部函式可以取得包含函式的區域變數
def callFunc(a, b):num = str(a + b)def getMessage():return 'A: ' + numreturn getMessageresult = callFunc(3, 5)print(result())# A: 8
13.3 語法糖「@」
我們來將開頭的範例改函式裝飾器,而不使用語法糖 (syntax candy)@
函式裝飾器
import datetimedef addNumbers(a, b):print(a + b)def theDecorate(func):def wrapper(a, b):print(datetime.datetime.now())func(a, b)print(datetime.datetime.now())return wrapperresult = theDecorate(addNumbers)result(3, 5)
語法糖「@」
import datetimedef addTimestamp(func):def wrapper(a, b):print(datetime.datetime.now())func(a, b)print(datetime.datetime.now())return wrapper@addTimestampdef addNumbers(a, b):print(a + b)addNumbers(3, 5)
在這簡單的範例中,使用語法糖(syntax candy)並沒有給我們帶來顯著的差異。這是因為我們的範例程式碼確實非常簡潔,而且函式只被呼叫了一次。
然而,在複雜的程式中,或是當一個函式被多次呼叫時,使用裝飾器的優勢就會更加明顯。它使得程式碼更具可讀性和可維護性,因為額外的功能被抽象到了裝飾器中,而不是直接嵌入在原始函式中。
此外,當你有多個函式需要相同的額外功能時,使用裝飾器可以幫助你避免代碼的重複,從而提高了代碼的重用性和可擴展性。
即使在簡單的例子中,使用語法糖也可以使程式碼更加清晰和精簡,同時在複雜的場景中,它的價值會更加突出。
