装饰器是 Python 中一种强大的工具,用于动态修改函数或类的行为,而无需修改其源代码。它基于高阶函数和闭包的概念,广泛应用于日志记录、权限验证、性能测试等场景。
定义
装饰器是一个接受函数作为参数并返回新函数的可调用对象(通常是函数或类)。
作用
语法糖
Python 提供 @decorator
语法,简化装饰器的使用。
函数作为对象
Python 中函数是一等公民,可以作为参数传递、返回值或赋值给变量。
闭包机制
装饰器利用闭包(Closure)保存被装饰函数的引用,并在新函数中调用它。
执行顺序
定义装饰器函数
接受一个函数作为参数,返回一个新函数。
编写新函数
在新函数中添加额外功能,并调用原函数。
应用装饰器
使用 @decorator
语法或手动调用装饰器。
记录函数的执行时间:
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} executed in {end_time - start_time:.4f} seconds")
return result
return wrapper
@timer_decorator
def heavy_computation(n):
time.sleep(n)
return "Done"
# 调用被装饰的函数
print(heavy_computation(2))
输出:
heavy_computation executed in 2.0023 seconds
Done
根据日志级别记录信息:
def log_decorator(level="INFO"):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{level}] Calling {func.__name__} with args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"[{level}] {func.__name__} returned {result}")
return result
return wrapper
return decorator
@log_decorator(level="DEBUG")
def add(a, b):
return a + b
# 调用被装饰的函数
print(add(3, 5))
输出:
[DEBUG] Calling add with args=(3, 5), kwargs={}
[DEBUG] add returned 8
8
统计函数调用次数:
class CallCounter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} has been called {self.count} times")
return self.func(*args, **kwargs)
@CallCounter
def greet(name):
return f"Hello, {name}!"
# 调用被装饰的函数
print(greet("Alice"))
print(greet("Bob"))
输出:
greet has been called 1 times
Hello, Alice!
greet has been called 2 times
Hello, Bob!
同时记录日志和执行时间:
@log_decorator(level="INFO")
@timer_decorator
def multiply(a, b):
return a * b
# 调用被装饰的函数
print(multiply(4, 5))
输出:
[INFO] Calling multiply with args=(4, 5), kwargs={}
multiply executed in 0.0000 seconds
[INFO] multiply returned 20
20
等价代码解析
@decorator
语法糖等价于:
def original_function():
pass
original_function = decorator(original_function)
函数属性保留
使用 functools.wraps
保留原函数的元信息(如 __name__
、__doc__
):
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before calling the function")
result = func(*args, **kwargs)
print("After calling the function")
return result
return wrapper
日志记录
自动记录函数调用信息。
权限验证
检查用户权限后再执行函数。
性能测试
测量函数执行时间。
缓存结果
使用 functools.lru_cache
实现函数结果缓存。
重试机制
在函数失败时自动重试。
装饰器顺序
多个装饰器从上到下依次应用:
@decorator1
@decorator2
def func():
pass
# 等价于 func = decorator1(decorator2(func))
装饰器副作用
装饰器在函数定义时立即执行,而非调用时。
类方法装饰器
装饰类方法时,需使用 @functools.wraps
保留方法绑定。
装饰器是 Python 中实现 AOP(面向切面编程)的核心工具,通过高阶函数和闭包机制,能够在不修改原代码的情况下增强函数功能。掌握装饰器的使用和原理,可以显著提升代码的可维护性和复用性。
from functools import wraps
def retry_decorator(max_retries=3):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
raise Exception("All retries failed")
return wrapper
return decorator
@retry_decorator(max_retries=2)
def risky_operation():
import random
if random.random() < 0.5:
raise ValueError("Something went wrong")
return "Success"
# 调用被装饰的函数
print(risky_operation())
输出(示例):
Attempt 1 failed: Something went wrong
Attempt 2 failed: Something went wrong
Traceback (most recent call last):
...
Exception: All retries failed