You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中如何在装饰器内部调用带该装饰器的函数实现重试

解决限流装饰器的重试问题

首先,你遇到的核心问题是:直接调用func(*args, **kwargs)时,执行的是未被装饰的原函数,完全绕开了限流检查逻辑。要实现带限流检查的重试,你需要重新触发整个wrapper的逻辑,而非直接调用原函数。

可行实现方案:循环重试(推荐)

用循环替代递归,避免栈溢出风险,同时可设置最大重试次数防止无限等待:

from functools import wraps
import time
import logging

LOGGER = logging.getLogger(__name__)

def rate_limiter(self, func: Callable):
    @wraps(func)
    def wrapper(*args, **kwargs):
        max_retries = 10  # 可根据需求调整最大重试次数
        retry_delay = 2   # 每次重试等待的秒数
        for attempt in range(max_retries):
            if is_request_allowed():
                LOGGER.info('Request allowed')
                return func(*args, **kwargs)
            else:
                LOGGER.info(f'Request not allowed, retrying in {retry_delay}s (attempt {attempt+1}/{max_retries})')
                time.sleep(retry_delay)
        # 超过最大重试次数后的处理
        LOGGER.error('Max retries exceeded, request failed')
        raise Exception('Rate limit exceeded after max retries')
    return wrapper

为什么直接调用func不行?

  • func是传入装饰器的原始函数对象,没有经过rate_limiter的包装,调用它不会触发限流检查逻辑,相当于绕过了你的限流规则。
  • wrapper才是包含完整限流判断的包装函数,只有调用wrapper(*args, **kwargs)才能重新执行限流检查流程。

备选方案:递归重试(注意栈溢出)

如果想用递归实现,可直接在else分支调用wrapper本身,但必须设置递归深度限制,避免无限递归导致栈溢出:

def rate_limiter(self, func: Callable):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if is_request_allowed():
            LOGGER.info('Request allowed')
            return func(*args, **kwargs)
        else:
            LOGGER.info('Request not allowed, retrying...')
            time.sleep(2)
            return wrapper(*args, **kwargs)  # 递归调用wrapper触发完整检查
    return wrapper

⚠️ 注意:这种方式默认无重试次数限制,建议额外添加参数控制递归次数。

优化建议

可以将重试次数、延迟时间作为装饰器参数传入,让装饰器更灵活:

def rate_limiter(max_retries=10, retry_delay=2):
    def decorator(func: Callable):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                if is_request_allowed():
                    LOGGER.info('Request allowed')
                    return func(*args, **kwargs)
                LOGGER.info(f'Retry {attempt+1}/{max_retries} in {retry_delay}s...')
                time.sleep(retry_delay)
            LOGGER.error('Max retries reached')
            raise Exception('Rate limit exceeded')
        return wrapper
    return decorator

# 使用方式示例
@rate_limiter(max_retries=5, retry_delay=3)
def my_api_request():
    # API请求逻辑
    pass

内容的提问来源于stack exchange,提问作者Oscar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 01:46:19