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

如何为任意参数数量的函数调用器添加正确的类型注解

实现带类型检查的通用函数调用器

我需要实现一个函数调用器fun_caller,它能接收任意函数及其对应参数并执行,但之前的两种方案都有局限:

现有方案的问题

方案一:仅支持固定参数数量

这个方案能让类型检查器识别参数的数量和类型是否正确,但只能处理恰好2个参数的函数,没法通用到任意参数数量的场景:

from typing import TypeVar
from collections.abc import Callable

T0 = TypeVar("T0")
T1 = TypeVar("T1")
T2 = TypeVar("T2")

def my_fun(a: str, b: int) -> None:
    print(int(a) + b)
    return None

def fun_caller(f: Callable[[T0, T1], T2], *args: tuple[T0, T1]) -> T2:
    return f(*args)

fun_caller(my_fun, "1", 2)

方案二:支持任意参数但无类型检查

这个方案能处理任意参数数量的函数,但类型检查器没法检测参数数量、类型错误,只能等运行时抛出TypeError:

from typing import TypeVar, Any
from collections.abc import Callable

T = TypeVar("T")

def my_fun(a: str, b: int) -> None:
    print(int(a) + b)
    return None

def fun_caller(f: Callable[..., T], *args: tuple[Any, ...]) -> T:
    return f(*args)

# 这里期望类型检查器报错:第一个参数应为str,且只需要2个参数而非3个,但实际不会
fun_caller(my_fun, 0, 2, "a")

通用解决方案

使用Python 3.10+引入的ParamSpec,结合TypeVar可以实现既支持任意参数数量和类型,又能让类型检查器正确校验的fun_caller:

from typing import TypeVar, ParamSpec
from collections.abc import Callable

# P用于捕获目标函数的参数签名,T用于捕获返回值类型
P = ParamSpec("P")
T = TypeVar("T")

def my_fun(a: str, b: int) -> None:
    print(int(a) + b)

def fun_caller(f: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
    return f(*args, **kwargs)

# 正确调用:类型检查通过
fun_caller(my_fun, "1", 2)

# 以下错误调用会被类型检查器直接识别:
# 错误1:参数数量过多
# fun_caller(my_fun, "1", 2, "extra")
# 错误2:第一个参数类型不匹配(应为str,传入了int)
# fun_caller(my_fun, 0, 2)

方案说明

  • ParamSpec("P")会完整捕获目标函数的所有参数信息,包括位置参数、关键字参数的类型和数量
  • Callable[P, T]约束传入的函数必须符合P定义的参数签名,返回值类型为T
  • *args: P.args和**kwargs: P.kwargs确保传入fun_caller的参数和目标函数的参数严格匹配
  • 主流类型检查器(如mypy、Pyright)会在静态检查阶段就识别出参数数量、类型不匹配的问题,不用等到运行时

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:18:34