五大实用 Python 装饰器模式,助力你的代码更高效、更优雅

五大实用 Python 装饰器模式,助力你的代码更高效、更优雅如果你已经用 Python 编程有一段时间 可能已经见过并使用过装饰器 虽然许多开发者都了解装饰器的基础用法 但收集一些有用且可复用的装饰器模式 可以显著提升你的代码质量和开发效率 本文将介绍五种值得加入你的工具箱的装饰器模式 每种模式都附

大家好,欢迎来到IT知识分享网。

如果你已经用 Python 编程有一段时间,可能已经见过并使用过装饰器。虽然许多开发者都了解装饰器的基础用法,但收集一些有用且可复用的装饰器模式,可以显著提升你的代码质量和开发效率。

本文将介绍五种值得加入你的工具箱的装饰器模式。每种模式都附有示例实现和实际应用案例。让我们开始吧!

五大实用 Python 装饰器模式,助力你的代码更高效、更优雅

点击查看 GitHub 上的完整代码


什么是装饰器?

在深入讲解之前,让我们快速回顾一下什么是装饰器。归根结底,装饰器是一种用于在不修改原始函数(或类)源码的情况下,增强其功能的函数。装饰器的一般用法如下:

@decorator def function():     pass 

这实际上等同于:

function = decorator(function) 

现在,让我们进入精彩内容吧。


1. 记忆化(Memoization)

假设你有一个函数,需要根据输入做一些耗时的计算,比如复杂的数学运算、大型数据集的处理、API 调用等。每次都重复计算其实很浪费资源。

下面是一个简单的记忆化装饰器:

def memoize(func):     """根据参数缓存函数的返回值。"""     cache = {}     def wrapper(*args, kwargs):         # 创建唯一标识本次调用的 key         key = str(args) + str(kwargs)         if key not in cache:             cache[key] = func(*args, kwargs)         return cache[key]     return wrapper 

示例:斐波那契数列

假设你要递归计算斐波那契数列,可以这样记忆化:

@memoize def fibonacci(n):     """计算第 n 个斐波那契数。"""     if n <= 1:         return n     return fibonacci(n-1) + fibonacci(n-2) # 没有记忆化时会很慢 result = fibonacci(50) print(f"第 50 个斐波那契数是 {result}") 

输出:

第 50 个斐波那契数是  

没有记忆化时,fibonacci(50) 由于递归调用会非常慢;而加上记忆化后,几乎瞬间完成计算。

适用场景: 当你需要重复处理相同输入且函数结果不会变化时,适合采用这种模式。


2. 日志记录(Logging)

你不总是希望在函数里到处插入 print 或 debug 语句,尤其是想在多个函数中实现统一、规范的日志记录时。

这个装饰器可以记录函数调用的相关信息,非常适合调试和监控:

import logging import functools def log_calls(func=None, level=logging.INFO):     """记录函数调用的参数和返回值。"""     def decorator(func):         @functools.wraps(func)         def wrapper(*args, kwargs):             args_str = ", ".join([str(a) for a in args])             kwargs_str = ", ".join([f"{k}={v}" for k, v in kwargs.items()])             all_args = f"{args_str}{', ' if args_str and kwargs_str else ''}{kwargs_str}"             logging.log(level, f"调用 {func.__name__}({all_args})")             result = func(*args, kwargs)             logging.log(level, f"{func.__name__} 返回 {result}")             return result         return wrapper     # 兼容 @log_calls 和 @log_calls(level=logging.DEBUG) 两种用法     if func is None:         return decorator     return decorator(func) 

示例:日志记录函数调用

logging.basicConfig(level=logging.INFO) @log_calls def divide(a, b):     return a / b # 这会自动记录调用和返回值 result = divide(10, 2) # 还可以自定义日志级别 @log_calls(level=logging.DEBUG) def multiply(a, b):     return a * b result = multiply(5, 4) 

适用场景: 适用于小型脚本、API 端点或批量作业调试时,统一记录函数调用信息。


3. 执行时间统计(Timing Execution)

有时你想快速了解函数运行所需的时间,尤其是涉及数据库、文件解析或模型训练等场景。

import time import functools def timeit(func):     """统计并打印函数的执行时间。"""     @functools.wraps(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 

示例:统计函数运行时间

@timeit def slow_function():     """一个故意运行缓慢的函数用于演示。"""     total = 0     for i in range():         total += i     return total result = slow_function()  # 会打印运行耗时 

输出:

slow_function 执行耗时 0.5370 秒 

适用场景: 这种装饰器适用于对简单函数做基准测试,帮助你发现优化空间。


4. 自动重试(Retry on Failure)

在和外部服务交互或执行不稳定操作时,失败后自动重试可以让代码更健壮。

def retry(max_attempts=3, delay_seconds=1, backoff_factor=2, exceptions=(Exception,)):     """在指定异常时自动重试函数。"""     def decorator(func):         @functools.wraps(func)         def wrapper(*args, kwargs):             attempts = 0             current_delay = delay_seconds             while attempts < max_attempts:                 try:                     return func(*args, kwargs)                 except exceptions as e:                     attempts += 1                     if attempts == max_attempts:                         logging.error(f"尝试 {attempts} 次后失败。最后的错误: {e}")                         raise                     logging.warning(                         f"第 {attempts} 次尝试失败,错误:{e}。{current_delay} 秒后重试..."                     )                     time.sleep(current_delay)                     current_delay *= backoff_factor         return wrapper     return decorator 

这个 retry 装饰器会在指定异常发生时自动重试函数,最多尝试 max_attempts 次。它实现了指数退避策略,即每次重试的间隔会倍增。你可以自定义最大重试次数、初始延迟、退避倍数和捕捉的异常类型。重试时会记录警告日志,最终失败时会记录错误并抛出最后一次异常。

示例:带重试机制的 API 查询

(确保已安装 requests 库)

import random import requests @retry(max_attempts=5, delay_seconds=1, exceptions=(requests.RequestException,)) def fetch_data(url):     """带重试逻辑的 API 数据获取。"""     response = requests.get(url, timeout=2)     response.raise_for_status()  # 4XX/5XX 响应抛出异常     return response.json() # 失败时会最多重试 5 次 try:     data = fetch_data('https://api.example.com/data')     print("数据获取成功!") except Exception as e:     print(f"所有重试均失败:{e}") 

适用场景: 适用于网络请求、不稳定 API 或任何 IO 密集型操作。


5. 输入验证(Input Validation)

你可以用装饰器自动验证函数输入,而无需让函数主体变得臃肿。

下面这个装饰器用于确保所有输入参数都是正整数:

def validate_positive_ints(func):     def wrapper(*args):         for arg in args:             if not isinstance(arg, int) or arg <= 0:                 raise ValueError(f"{arg} 必须为正整数")         return func(*args)     return wrapper 

示例:验证正整数输入

@validate_positive_ints def calculate_area(length, width):     return length * width print(calculate_area(5, 10))      # 正常输出 50 print(calculate_area(-1, 10))     # 抛出 ValueError 

输出:

50 --------------------------------------------------------------------------- ValueError                                Traceback (most recent call last)  in ()       4        5 print(calculate_area(5, 10)) ----> 6 print(calculate_area(-1, 10))  in wrapper(*args)       3         for arg in args:       4             if not isinstance(arg, int) or arg <= 0: ----> 5                 raise ValueError(f"{arg} 必须为正整数")       6         return func(*args)       7     return wrapper ValueError: -1 必须为正整数 

适用场景: 适合用于数据处理管道和用户输入的参数校验。


总结

可以把装饰器看作是为函数“加装”额外行为的优雅工具。我们介绍的五种模式 —— 记忆化、日志记录、时间统计、自动重试和输入验证 —— 是我日常开发中的常用技巧。

将这些装饰器模式加入你的项目(或者更好地,将它们收集成一个实用工具模块),你会写出更简洁、可维护性更高的代码,也能节省大量重复劳动。

不妨思考一下,代码中哪些功能可以抽象成装饰器,并在全项目内统一应用。当你习惯用这种思路审视代码时,会发现装饰器的用武之地无处不在。

你最喜欢哪一种装饰器模式?你有没有自己写过、不可或缺的专属装饰器?欢迎一起交流分享!

五大实用 Python 装饰器模式,助力你的代码更高效、更优雅

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/178773.html

(0)
上一篇 2025-05-16 08:00
下一篇 2025-05-16 08:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信