
本文详解如何在 python 装饰器内部获取并判断被装饰函数的返回值(如 http 状态码),从而实现条件化重试逻辑,避免盲目重试,并给出可直接运行的完整示例与关键注意事项。
本文详解如何在 python 装饰器内部获取并判断被装饰函数的返回值(如 http 状态码),从而实现条件化重试逻辑,避免盲目重试,并给出可直接运行的完整示例与关键注意事项。
在 Python 中,装饰器本质上是对函数调用过程的封装,而非对函数定义的静态修饰。这意味着:装饰器中的逻辑(如重试控制)必须在实际执行被装饰函数后,才能访问其返回值——你无法在函数执行前“预知”返回值,也不能将返回值作为装饰器参数传入(因为此时函数尚未运行)。因此,正确做法是在装饰器内部调用 func(*args, **kwargs),捕获其返回值,再根据该值决定是否重试。
以下是一个符合需求的、生产就绪的重试装饰器实现:
import requests
import time
from functools import wraps
def retry_on_5xx(retries=3, delay=3):
"""
仅在响应状态码为 5xx 时重试;4xx(如 404)等客户端错误不重试。
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(retries + 1): # +1 表示首次尝试也计入循环
try:
result = func(*args, **kwargs) # ✅ 关键:执行函数并获取返回值
if isinstance(result, requests.Response):
status = result.status_code
elif isinstance(result, int): # 直接返回 status_code 的场景
status = result
else:
raise ValueError(f"Unsupported return type: {type(result)}")
# ✅ 核心逻辑:仅当 status 是 5xx 时才重试(且未达最大重试次数)
if 500 <p>⚠️ <strong>关键注意事项</strong>:</p>
-
不要混淆装饰器参数与函数返回值:
@retry_on_5xx(retries=3)中的retries是装饰器配置,而status_code是被装饰函数运行后产生的结果,二者生命周期完全不同; - 避免全局/环境变量传递状态:这会破坏函数纯度、引发并发问题,且违背装饰器设计原则;
-
优先返回
Response对象:比仅返回status_code更灵活(可后续读取json()、text等); -
显式处理异常与非 5xx 错误:如
requests.exceptions.Timeout或404,应立即终止重试,防止无意义轮询; -
使用
@wraps(func):保留原函数的__name__、__doc__等元信息,利于调试和文档生成。
通过将返回值检查逻辑置于装饰器内部的主循环中,你既能精准控制重试边界,又能保持代码清晰、可测试、符合 Python 惯例。










