甲居工作室

13.Python 裝飾器 (Decorator)

日期:2024/04/11

13.Python 裝飾器 (Decorator)

當談到 Python 的裝飾器(Decorator)時,它們是一種強大的工具,可以在不改變函式本身的情況下,動態地擴展函式的功能。想像你有一個函式,你想要在不更改它的程式碼的情況下,將某些功能添加到它上面。這就是裝飾器的用武之地。

13.1 介紹

裝飾器本身就是函式,但是它接受另一個函式作為參數,然後返回一個新的函式,或者修改傳遞給它的函式,以添加額外的功能。這聽起來有點抽象,但是讓我們看一個簡單的例子來幫助理解。

假設你有一個函式 addNumbers(),它只是簡單地相加兩個數值:

  1. def addNumbers(a, b):
  2. print(a + b)

現在,你想要在每次呼叫 addNumbers() 時,都在打印消息之前和之後加上一些其他的動作,比如時間戳記。你可以通過創建一個裝飾器來實現這一點:

  1. import datetime
  2. def addTimestamp(func):
  3. def wrapper(a, b):
  4. print(datetime.datetime.now())
  5. func(a, b)
  6. print(datetime.datetime.now())
  7. return wrapper
  8. @addTimestamp
  9. def addNumbers(a, b):
  10. print(a + b)
  11. addNumbers(3, 5)

好吧!如果還是不清楚我們逐步來說明。

13.2 Python 函式就是物件

11.Python 類別 (Class)章節時有提到呼叫函式時可以不先加上()並且設定一個參數給他。

  1. def addNumbers(a, b):
  2. print(a + b)
  3. addTwo = addNumbers
  4. addTwo(3, 5)

當然也可以在函式裡再定義另一個函式。

  1. def addNumbers(a, b):
  2. def getAnswer():
  3. return 'A: '
  4. result = getAnswer() + str(a + b)
  5. return result
  6. print(addNumbers(3, 5))
  7. # A: 8

甚至函式可以當做參數傳給另一個函式

  1. def getAnswer(num):
  2. return 'A: ' + str(num)
  3. def callFunc(func):
  4. num = 3 + 5
  5. return func(num)
  6. print(callFunc(getAnswer))
  7. # A: 8

函式可以回傳函式

  1. def callFunc():
  2. def addNumbers():
  3. return 3 + 5
  4. return addNumbers
  5. result = callFunc()
  6. print(result())
  7. # 8

最後再說一個觀念內部函式可以取得包含函式的區域變數

  1. def callFunc(a, b):
  2. num = str(a + b)
  3. def getMessage():
  4. return 'A: ' + num
  5. return getMessage
  6. result = callFunc(3, 5)
  7. print(result())
  8. # A: 8

13.3 語法糖「@」

我們來將開頭的範例改函式裝飾器,而不使用語法糖 (syntax candy)@

函式裝飾器

  1. import datetime
  2. def addNumbers(a, b):
  3. print(a + b)
  4. def theDecorate(func):
  5. def wrapper(a, b):
  6. print(datetime.datetime.now())
  7. func(a, b)
  8. print(datetime.datetime.now())
  9. return wrapper
  10. result = theDecorate(addNumbers)
  11. result(3, 5)

語法糖「@」

  1. import datetime
  2. def addTimestamp(func):
  3. def wrapper(a, b):
  4. print(datetime.datetime.now())
  5. func(a, b)
  6. print(datetime.datetime.now())
  7. return wrapper
  8. @addTimestamp
  9. def addNumbers(a, b):
  10. print(a + b)
  11. addNumbers(3, 5)

在這簡單的範例中,使用語法糖(syntax candy)並沒有給我們帶來顯著的差異。這是因為我們的範例程式碼確實非常簡潔,而且函式只被呼叫了一次。

然而,在複雜的程式中,或是當一個函式被多次呼叫時,使用裝飾器的優勢就會更加明顯。它使得程式碼更具可讀性和可維護性,因為額外的功能被抽象到了裝飾器中,而不是直接嵌入在原始函式中。

此外,當你有多個函式需要相同的額外功能時,使用裝飾器可以幫助你避免代碼的重複,從而提高了代碼的重用性和可擴展性。

即使在簡單的例子中,使用語法糖也可以使程式碼更加清晰和精簡,同時在複雜的場景中,它的價值會更加突出。

延伸閱讀

1. NumPy 套件 (入門)

Python 在處理資料數據領域非常流行,有許多強大的套件和工具可供使用。 以下是 Python 資料科學中常用的一些主要庫和工具: NumPy: Python語言的一個擴充程式庫。支援高階大規模…

Read more

2. Matplotlib套件 (視覺化資料)

NumPy 套件 (視覺化資料)

Read more