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

如何在不使用Any类型的情况下为tenacity重试包装函数添加类型标注?

如何在不使用Any类型的情况下为tenacity重试包装函数添加类型标注?

当然可以!ParamSpec正是解决这类问题的绝佳方案,它能让我们精准复用原函数的参数签名和返回值类型,彻底摆脱Any的模糊标注,让类型检查器准确识别所有约束。

先给你看改造后的代码,完全符合类型安全要求:

from typing import ParamSpec, TypeVar
import tenacity

# 定义参数规格和返回值类型变量,用来捕获原函数的类型信息
P = ParamSpec("P")
R = TypeVar("R")

# 假设这是你需要添加重试逻辑的原函数,先给它加上明确的类型标注
def foo(a: int, b: str) -> None:
    print(f"执行foo:a={a}, b={b}")

@tenacity.retry
def foo_with_retry(*args: P.args, **kwargs: P.kwargs) -> R:
    # 这里的P和R会自动匹配foo的参数和返回值类型
    return foo(*args, **kwargs)

如果要做一个可复用的通用重试装饰器(能套在任意函数上),写法会更灵活:

from typing import ParamSpec, TypeVar, Callable
import tenacity

P = ParamSpec("P")
R = TypeVar("R")

def with_retry(func: Callable[P, R]) -> Callable[P, R]:
    @tenacity.retry
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
        return func(*args, **kwargs)
    return wrapper

# 直接用这个装饰器包装任意带类型标注的函数
@with_retry
def foo(a: int, b: str) -> None:
    print(f"执行foo:a={a}, b={b}")

@with_retry
def add(x: float, y: float) -> float:
    return x + y

简单说下原理

  • ParamSpec("P") 会完整捕获被包装函数的参数签名(包括位置参数、关键字参数的具体类型)
  • TypeVar("R") 用来捕获被包装函数的返回值类型
  • 通过Callable[P, R],我们把包装函数的类型和原函数严格绑定,像mypy、pyright这类静态类型检查工具,能准确识别参数约束,再也不用依赖模糊的Any类型。

这样改造后,不仅类型标注更严谨,还能让检查工具帮你提前发现参数传递错误——比如给foo_with_retry传字符串类型的a,检查器会直接报错提示。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 08:07:59