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

如何在Python客户端中优雅实现可复用的重试装饰器?

解决类实例中复用重试装饰器的问题

核心问题在于:类定义阶段,装饰器语法@retry会立即执行,但此时类的实例还未创建,self.retry根本不存在,自然无法引用。下面提供几种解耦重试逻辑、实现复用的方案:

方案一:带参数的函数式装饰器(最直接)

把重试逻辑封装成支持参数配置的函数式装饰器,既可以直接在方法上固定参数,也能通过类的初始化参数动态传递配置:

import time
from functools import wraps

def retry(max_retries=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_retries - 1:
                        raise
                    time.sleep(delay)
        return wrapper
    return decorator

# 方式1:直接在方法上指定固定重试参数
class MyAPIClass1:
    @retry(max_retries=3, delay=1)
    def method_that_might_fail(self):
        # 可能抛出异常的业务代码
        pass

# 方式2:通过类初始化参数动态配置重试规则
class MyAPIClass2:
    def __init__(self, max_retries=3, delay=1):
        # 动态给方法绑定带实例配置的重试逻辑
        self.method_that_might_fail = retry(max_retries, delay)(self.method_that_might_fail)
    
    def method_that_might_fail(self):
        # 可能抛出异常的业务代码
        pass

方案二:基于描述符的装饰器(适配实例级配置)

如果需要让重试规则和实例绑定(比如不同实例使用不同的重试次数),可以把Retry实现为描述符,调用时自动读取实例的配置:

import time
from functools import wraps

class Retry:
    def __init__(self, max_retries_attr='max_retries', delay_attr='delay'):
        # 指定实例中存储重试配置的属性名称
        self.max_retries_attr = max_retries_attr
        self.delay_attr = delay_attr

    def __call__(self, func):
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            max_retries = getattr(self, self.max_retries_attr)
            delay = getattr(self, self.delay_attr)
            for attempt in range(max_retries):
                try:
                    return func(self, *args, **kwargs)
                except Exception as e:
                    if attempt == max_retries - 1:
                        raise
                    time.sleep(delay)
        return wrapper

class MyAPIClass:
    def __init__(self, max_retries=3, delay=1):
        self.max_retries = max_retries
        self.delay = delay

    @Retry()  # 自动读取当前实例的max_retries和delay属性
    def method_that_might_fail(self):
        # 可能抛出异常的业务代码
        pass

方案三:类装饰器批量处理多方法

如果类中多个方法都需要重试逻辑,可以用类装饰器批量给指定方法添加重试规则:

import time
from functools import wraps

def add_retry_to_methods(max_retries=3, delay=1, method_prefix='fetch_'):
    def decorator(cls):
        for name, method in vars(cls).items():
            # 给符合前缀规则的方法批量添加重试
            if callable(method) and name.startswith(method_prefix):
                @wraps(method)
                def wrapper(self, *args, **kwargs):
                    for attempt in range(max_retries):
                        try:
                            return method(self, *args, **kwargs)
                        except Exception as e:
                            if attempt == max_retries - 1:
                                raise
                            time.sleep(delay)
                    setattr(cls, name, wrapper)
        return cls
    return decorator

@add_retry_to_methods(max_retries=3, delay=1, method_prefix='fetch_')
class MyAPIClass:
    def fetch_data(self):
        # 可能抛出异常的业务代码
        pass
    
    def fetch_user_info(self):
        # 可能抛出异常的业务代码
        pass

关键思路总结

  • 避免在类定义阶段直接引用实例属性作为装饰器,因为此时实例尚未创建
  • 优先选择函数式装饰器实现基础重试逻辑,灵活度最高
  • 若需和实例配置联动,描述符或动态装饰方案更适配
  • 多方法需重试时,类装饰器可大幅减少重复代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:22:12