装饰器中捕获并重试异常需用两层嵌套函数:外层接收重试参数,内层返回带 try/except 和 time.sleep 的 async/sync wrapper,并用 @functools.wraps 保留元信息,精确捕获指定异常,最后一次失败必须重新抛出。

装饰器里怎么捕获并重试异常
核心是用 try/except 包住被装饰函数的调用,捕获指定异常后延迟重试。不能直接在装饰器函数体里写逻辑,必须返回一个闭包(即实际执行的包装函数),否则每次调用都会走一遍初始化逻辑。
常见错误是把重试逻辑写在装饰器工厂函数里,导致只重试一次就退出;或者没用 functools.wraps,导致原函数的 __name__、__doc__ 丢失,调试和反射时出问题。
- 用
@functools.wraps(func)修饰内部包装函数,保留元信息 - 重试前加
time.sleep(delay),避免密集重试打垮下游 - 捕获异常要用具体类型(如
requests.exceptions.ConnectionError),别用裸except: - 最后一次失败必须重新抛出异常,不能静默吞掉
如何支持可配置的重试次数和延迟时间
需要两层嵌套:外层是装饰器工厂函数(接收 max_retries、delay 等参数),内层才是真正的装饰器。这是 Python 装饰器带参的标准写法。
如果只写一层函数,Python 会把被装饰函数直接传给它,根本收不到你写的 max_retries=3 这类参数。
def retry(max_retries=3, delay=1):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for i in range(max_retries + 1):
try:
return func(*args, **kwargs)
except Exception as e:
if i == max_retries:
raise
time.sleep(delay)
return wrapper
return decorator
注意 range(max_retries + 1):总共执行 max_retries + 1 次(首次 + 重试),否则会少试一次。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
为什么 requests 请求重试要小心连接异常类型
用 requests 时,不是所有网络异常都该重试。比如 requests.exceptions.HTTPError(4xx/5xx)中,404 或 400 是客户端问题,重试没意义;而 ConnectionError、Timeout、TooManyRedirects 才适合重试。
硬编码重试所有异常,可能把业务逻辑错误也反复重放,造成重复扣款或发信。
- 推荐显式列出要重试的异常类:
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): - 用
isinstance(e, tuple)判断更安全,避免继承关系漏判 - 生产环境建议加日志:每次重试记录
func.__name__、当前重试次数、异常类型
异步函数(async def)怎么加重试装饰器
普通同步装饰器对 async def 函数无效——它返回的是协程对象,不是结果;直接 await 必须在包装函数里做,且包装函数本身也得是 async def。
常见错误是忘了在 wrapper 前加 async,或在 await func(...) 外面套了 loop.run_until_complete(),破坏异步上下文。
def async_retry(max_retries=3, delay=1):
def decorator(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
for i in range(max_retries + 1):
try:
return await func(*args, **kwargs)
except Exception as e:
if i == max_retries:
raise
await asyncio.sleep(delay)
return wrapper
return decorator
如果被装饰函数是异步的,但装饰器是同步的,调用后你拿到的是一个未 await 的协程对象,不报错但永远不执行——这种 bug 很难察觉。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










