Python实用装饰器提升开发效率
Python实用装饰器提升开发效率
装饰器是 Python 中一项强大而灵活的功能,它允许我们在不修改原始代码的情况下,为函数或类添加额外的功能。无论是性能优化、调试辅助还是代码健壮性提升,装饰器都能让我们的开发工作事半功倍。
下面分享 10 个简单但超级有用的自定义装饰器,每一个都配有完整的代码实现和使用示例。
1. @timer - 测量函数执行时间
优化代码性能时,了解函数的执行时间至关重要。@timer 装饰器可以轻松跟踪函数的运行时长:
import timedef 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:.2f} 秒")return resultreturn wrapper@timer
def process_large_dataset():"""模拟处理大型数据集"""data = [x ** 2 for x in range(1000000)]return sum(data)# 使用示例
result = process_large_dataset()
print(f"处理结果: {result}")
2. @memoize - 缓存函数结果
对于计算成本高的函数,@memoize 可以缓存结果,避免相同输入的重复计算:
def memoize(func):cache = {}def wrapper(*args):if args in cache:print(f"从缓存中获取结果: {args} -> {cache[args]}")return cache[args]result = func(*args)cache[args] = resultprint(f"计算并缓存结果: {args} -> {result}")return resultreturn wrapper@memoize
def fibonacci(n):if n <= 1:return nreturn fibonacci(n - 1) + fibonacci(n - 2)# 使用示例
print(fibonacci(10)) # 第一次计算
print(fibonacci(10)) # 从缓存获取
3. @validate_input - 参数验证
确保函数接收到的参数符合预期标准:
def validate_input(*expected_types):def decorator(func):def wrapper(*args, **kwargs):for i, (arg, expected_type) in enumerate(zip(args, expected_types)):if not isinstance(arg, expected_type):raise TypeError(f"参数 {i} 应该是 {expected_type} 类型,但得到的是 {type(arg)}")return func(*args, **kwargs)return wrapperreturn decorator@validate_input(list, int)
def get_list_slice(data, n):"""获取列表的前n个元素"""return data[:n]# 使用示例
try:result = get_list_slice([1, 2, 3, 4, 5], 3)print(f"切片结果: {result}")get_list_slice("不是列表", 3) # 这会抛出异常
except TypeError as e:print(f"错误: {e}")
4. @log_results - 记录函数输出
在复杂的数据分析任务中,记录函数结果对于调试和监控非常有帮助:
def log_results(log_file="function_results.log"):def decorator(func):def wrapper(*args, **kwargs):result = func(*args, **kwargs)with open(log_file, "a", encoding="utf-8") as f:f.write(f"{func.__name__} - 参数: {args} {kwargs} - 结果: {result}\n")return resultreturn wrapperreturn decorator@log_results("calculations.log")
def calculate_statistics(numbers):"""计算数据的统计信息"""if not numbers:return Nonereturn {'sum': sum(numbers),'mean': sum(numbers) / len(numbers),'max': max(numbers),'min': min(numbers)}# 使用示例
stats = calculate_statistics([10, 20, 30, 40, 50])
print(f"统计结果: {stats}")
5. @suppress_errors - 优雅的错误处理
防止意外错误中断整个执行流程:
def suppress_errors(default_return=None):def decorator(func):def wrapper(*args, **kwargs):try:return func(*args, **kwargs)except Exception as e:print(f"函数 {func.__name__} 执行出错: {e}")return default_returnreturn wrapperreturn decorator@suppress_errors(default_return=0)
def safe_divide(a, b):"""安全的除法运算"""return a / b# 使用示例
print(f"10 / 2 = {safe_divide(10, 2)}")
print(f"10 / 0 = {safe_divide(10, 0)}") # 不会崩溃,返回默认值0
6. @validate_output - 输出验证
确保函数输出符合质量标准:
def validate_output(validation_func):def decorator(func):def wrapper(*args, **kwargs):result = func(*args, **kwargs)if validation_func(result):return resultelse:raise ValueError(f"函数 {func.__name__} 的输出未通过验证: {result}")return wrapperreturn decoratordef is_positive_number(x):"""验证是否为正数"""return isinstance(x, (int, float)) and x > 0@validate_output(is_positive_number)
def process_value(x):"""处理数值,确保返回正数"""return abs(x) + 1# 使用示例
try:print(f"处理 -5: {process_value(-5)}")print(f"处理 10: {process_value(10)}")
except ValueError as e:print(f"验证失败: {e}")
7. @retry - 自动重试机制
在网络请求等可能临时失败的操作中自动重试:
import time
import randomdef retry(max_attempts=3, delay=1, backoff=2):def decorator(func):def wrapper(*args, **kwargs):attempts = 0current_delay = delaywhile attempts < max_attempts:try:return func(*args, **kwargs)except Exception as e:attempts += 1if attempts == max_attempts:raise Exception(f"超过最大重试次数 ({max_attempts}),最后错误: {e}")print(f"第 {attempts} 次尝试失败,{current_delay} 秒后重试... 错误: {e}")time.sleep(current_delay)current_delay *= backoff # 指数退避return wrapperreturn decorator@retry(max_attempts=3, delay=1)
def unreliable_operation():"""模拟可能失败的操作"""if random.random() < 0.7: # 70% 的失败率raise Exception("随机失败!")return "操作成功!"# 使用示例
try:result = unreliable_operation()print(result)
except Exception as e:print(f"最终失败: {e}")
8. @debug - 调试助手
自动打印函数的输入参数和返回值,简化调试过程:
def debug(verbose=True):def decorator(func):def wrapper(*args, **kwargs):if verbose:print(f"🔍 调用 {func.__name__}")print(f" 参数: {args}")print(f" 关键字参数: {kwargs}")result = func(*args, **kwargs)if verbose:print(f" 返回值: {result}")print(f"✅ {func.__name__} 执行完成\n")return resultreturn wrapperreturn decorator@debug(verbose=True)
def complex_calculation(a, b, coefficient=1.5):"""执行复杂计算"""intermediate = (a ** 2 + b ** 2) ** 0.5return intermediate * coefficient# 使用示例
result = complex_calculation(3, 4, coefficient=2)
9. @deprecated - 标记过时函数
当函数不再推荐使用时,向用户发出警告:
import warningsdef deprecated(replacement=None):def decorator(func):def wrapper(*args, **kwargs):message = f"函数 '{func.__name__}' 已过时,将在未来版本中移除。"if replacement:message += f" 请使用 '{replacement}' 代替。"warnings.warn(message, DeprecationWarning, stacklevel=2)return func(*args, **kwargs)return wrapperreturn decorator@deprecated(replacement="new_data_processor")
def old_data_processor(data):"""旧的数据处理函数"""return [x * 2 for x in data]def new_data_processor(data):"""新的数据处理函数"""return [x ** 2 for x in data]# 使用示例
data = [1, 2, 3, 4, 5]
result = old_data_processor(data) # 会显示过时警告
print(f"旧方法结果: {result}")
10. @visualize_results - 自动可视化
为数据分析函数自动生成可视化结果:
import matplotlib.pyplot as pltdef visualize_results(title=None):def decorator(func):def wrapper(*args, **kwargs):result = func(*args, **kwargs)# 创建可视化plt.figure(figsize=(10, 6))if isinstance(result, (list, tuple)):plt.plot(result, marker='o', linestyle='-', color='blue')plt.xlabel('索引')plt.ylabel('值')elif isinstance(result, dict):keys = list(result.keys())values = list(result.values())plt.bar(keys, values, color='skyblue')plt.xlabel('键')plt.ylabel('值')plot_title = title or f"{func.__name__} 结果可视化"plt.title(plot_title)plt.grid(True, alpha=0.3)plt.tight_layout()plt.show()return resultreturn wrapperreturn decorator@visualize_results("月度销售数据趋势")
def analyze_sales_trend():"""模拟分析销售趋势"""# 模拟月度销售数据months = ['1月', '2月', '3月', '4月', '5月', '6月']sales = [120, 150, 130, 170, 200, 180]return dict(zip(months, sales))# 使用示例
sales_data = analyze_sales_trend()
print(f"销售数据: {sales_data}")
总结
这些装饰器展示了 Python 装饰器的强大威力。通过简单的 @ 语法,我们就能为函数添加缓存、日志、验证、重试等复杂功能,而无需修改原始函数代码。
在实际项目中,你可以根据具体需求组合使用这些装饰器,或者创建自己的定制装饰器。掌握装饰器不仅能让你的代码更加简洁优雅,还能显著提升开发效率和代码质量。
使用技巧:
- 多个装饰器可以堆叠使用,执行顺序是从下往上
- 使用
functools.wraps可以保留原函数的元信息 - 装饰器也可以接受参数,实现更灵活的功能配置
