今天我們將學習 Python 中一個非常強大的功能——裝飾器(Decorators)。裝飾器是 Python 函數式編程的重要特性,它們允許我們修改或增強現有的函數或方法,而不需要改變它們的原始程式碼。裝飾器在現實開發中常被用於日誌記錄、權限驗證、性能計算等場景。
裝飾器是 Python 提供的一種語法糖,用於在不改變原始函數程式碼的情況下,為函數增添額外的功能。可以將裝飾器理解為一個函數,它接收另一個函數作為輸入,並返回一個增強版的函數。
def my_decorator(func):
def wrapper():
print("執行前")
func()
print("執行後")
return wrapper
@my_decorator
def say_hello():
print("Hello, world!")
say_hello()
在這個範例中,my_decorator
是一個裝飾器,它在 say_hello
函數執行前後增加了額外的行為。透過使用 @my_decorator
,我們把裝飾器應用到了 say_hello
函數上。
輸出結果:
執行前
Hello, world!
執行後
裝飾器的核心優勢是重用性和簡化程式碼。假設我們在多個函數中需要執行相同的額外邏輯(例如,計算函數的執行時間、驗證使用者權限等),那麼我們可以通過裝飾器來統一管理這些邏輯,而不必為每個函數手動編寫重複的程式碼。
在這裡,我們將定義一個裝飾器,該裝飾器可以記錄被裝飾函數的執行時間。
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函數 {func.__name__} 執行時間:{end_time - start_time:.4f} 秒")
return result
return wrapper
@timer
def example_function():
time.sleep(2)
print("函數正在執行...")
example_function()
這個範例使用了 time
模組來計算 example_function
的執行時間。透過 @timer
,我們把這個計時功能應用到了 example_function
函數上。
輸出結果:
函數正在執行...
函數 example_function 執行時間:2.0001 秒
我們也可以編寫可以傳遞參數的裝飾器,讓它的功能更加靈活。例如,寫一個裝飾器來控制日誌的打印級別。
def log(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == 'info':
print(f"[INFO] 執行 {func.__name__} 函數")
elif level == 'error':
print(f"[ERROR] 執行 {func.__name__} 函數")
return func(*args, **kwargs)
return wrapper
return decorator
@log('info')
def process_data():
print("處理數據中...")
process_data()
在這個範例中,我們定義了一個帶有參數的裝飾器 log
,通過傳遞不同的日誌級別來控制輸出的內容。
輸出結果:
[INFO] 執行 process_data 函數
處理數據中...
裝飾器在開發過程中非常常見,特別是當我們需要為多個函數添加相同的功能時。以下是幾個常見的應用場景:
裝飾器可以自動為函數添加日誌輸出,用於追蹤程式執行過程。
def log_execution(func):
def wrapper(*args, **kwargs):
print(f"執行 {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_execution
def my_function():
print("這是一個業務邏輯函數")
my_function()
在 Web 開發中,常常需要為某些敏感操作進行權限檢查。裝飾器可以方便地在函數調用前進行權限驗證。
def check_permission(role):
def decorator(func):
def wrapper(*args, **kwargs):
if role == 'admin':
return func(*args, **kwargs)
else:
print("權限不足,無法執行此操作")
return wrapper
return decorator
@check_permission('user')
def delete_user():
print("使用者已刪除")
delete_user()
這裡的裝飾器根據使用者的角色來決定是否執行刪除操作。
在 Python 中,我們可以同時使用多個裝飾器來為同一個函數增加多種功能。巢狀裝飾器的使用非常簡單,只需要在函數定義上連續使用多個 @
符號即可。
@log_execution
@timer
def complex_calculation():
time.sleep(1)
print("執行複雜計算中...")
complex_calculation()
輸出結果:
執行 complex_calculation
執行複雜計算中...
函數 complex_calculation 執行時間:1.0002 秒
這兩個練習涉及 Python 的裝飾器,裝飾器是一種用來修改或增強函數行為的設計模式。通過裝飾器,你可以實現驗證、記錄等功能,而不需要更改原本的函數邏輯。以下是每個練習的詳細說明與範例代碼。
# 定義驗證正數的裝飾器
def validate_positive_number(func):
def wrapper(*args, **kwargs):
for arg in args: # 檢查所有傳入參數
if not isinstance(arg, (int, float)) or arg <= 0:
print(f"錯誤:{arg} 不是正數!")
return # 如果遇到錯誤值,停止執行函數
return func(*args, **kwargs)
return wrapper
# 應用裝飾器的函數
@validate_positive_number
def process_number(n):
print(f"處理數字: {n}")
# 測試程式
process_number(10) # 正數,應該正常執行
process_number(-5) # 負數,應該提示錯誤
process_number(0) # 0,應該提示錯誤
*args, **kwargs
:這樣可以處理任意數量的參數。isinstance(arg, (int, float))
:確保傳入的參數是整數或浮點數。# 定義記錄調用次數的裝飾器
def count_calls(func):
count = 0 # 記錄函數調用次數
def wrapper(*args, **kwargs):
nonlocal count # 使用 nonlocal 來修改外層變數
count += 1
print(f"函數 {func.__name__} 已被調用 {count} 次")
return func(*args, **kwargs)
return wrapper
# 應用裝飾器的函數
@count_calls
def say_hello():
print("Hello!")
# 測試程式
say_hello() # 第一次調用
say_hello() # 第二次調用
say_hello() # 第三次調用
count
:裝飾器內部變數,用來計算函數的調用次數。nonlocal count
:讓內部函數可以修改外層的 count
變數。count
會自動遞增並打印總次數。這兩個練習展示了如何使用裝飾器來處理函數參數驗證和函數調用次數記錄的功能。裝飾器提供了一種簡潔的方式來增強函數行為,無需修改原本的函數邏輯。
裝飾器是一個非常有用的工具,能夠讓我們的程式碼更具模組化與可讀性。通過將公共邏輯抽象到裝飾器中,我們可以減少重複程式碼,提高程式的靈活性與可維護性。
明天的主題:Python 中的生成器(Generators)與迭代器(Iterators)