裝飾器(decorators)是 Python 中的一種高級特性,它允許開發者修改函數或方法的行為,而不改變其定義。裝飾器通常用于日志記錄、權限檢查、性能測量等場景。裝飾器是通過在函數定義的前一行加上 @decorator_name
來使用的。
基本用法
裝飾器本質上是一個函數,它接受一個函數作為參數,并返回一個新的函數。以下是一個簡單的裝飾器示例:
def my_decorator(func):def wrapper():print("Something is happening before the function is called.")func()print("Something is happening after the function is called.")return wrapper@my_decorator
def say_hello():print("Hello!")say_hello()
輸出:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
在這個例子中:
my_decorator
是裝飾器函數。say_hello
是被裝飾的函數。@my_decorator
語法相當于say_hello = my_decorator(say_hello)
。
帶參數的裝飾器
如果需要在裝飾器中傳遞參數,可以使用多層嵌套函數來實現:
def repeat(num_times):def decorator_repeat(func):def wrapper(*args, **kwargs):for _ in range(num_times):func(*args, **kwargs)return wrapperreturn decorator_repeat@repeat(num_times=3)
def greet(name):print(f"Hello {name}")greet("World")
輸出:
Hello World
Hello World
Hello World
在這個例子中:
repeat
是一個帶參數的裝飾器工廠,它返回一個裝飾器。decorator_repeat
是實際的裝飾器。wrapper
是包裝函數,負責多次調用被裝飾的函數func
。
類裝飾器
裝飾器也可以用于類。類裝飾器是通過定義一個實現 __call__
方法的類來實現的:
class MyDecorator:def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print("Class-based decorator before function call.")result = self.func(*args, **kwargs)print("Class-based decorator after function call.")return result@MyDecorator
def say_goodbye():print("Goodbye!")say_goodbye()
輸出:
Class-based decorator before function call.
Goodbye!
Class-based decorator after function call.
在這個例子中:
MyDecorator
類實現了__call__
方法,使其實例可以像函數一樣被調用。say_goodbye
函數被MyDecorator
實例裝飾。
裝飾器的實際應用
裝飾器在實際開發中非常有用,以下是一些常見的應用場景:
- 日志記錄:在函數執行前后記錄日志。
- 權限檢查:在執行函數前檢查用戶是否有權限。
- 性能測量:計算函數執行時間。
- 緩存:緩存函數的返回值,以提高性能。
- 輸入校驗:在函數執行前校驗輸入參數。
示例:日志記錄裝飾器
import functoolsdef log_decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f"Calling {func.__name__} with {args} and {kwargs}")result = func(*args, **kwargs)print(f"{func.__name__} returned {result}")return resultreturn wrapper@log_decorator
def add(a, b):return a + badd(2, 3)
輸出:
Calling add with (2, 3) and {}
add returned 5
在這個例子中:
@functools.wraps(func)
保留了被裝飾函數的元數據(如文檔字符串和函數名)。log_decorator
在函數執行前后打印日志信息。
裝飾器是一個強大而靈活的工具,能夠極大地增強代碼的可復用性和可讀性。通過合理使用裝飾器,可以使代碼更加簡潔、優雅。