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

如何在Python Protocol中兼容任意args和kwargs并校验首个参数

解决方案:定义匹配首参数的函数Protocol

问题分析

你之前的Protocol定义要求函数必须显式接受*args和**kwargs,但目标函数(比如f)并没有声明这些可变参数,因此mypy判定类型不兼容。要实现「仅校验第一个参数类型,忽略后续任意参数」的需求,可以用以下两种方法:

方法一:使用ParamSpec(Python 3.10+ 推荐)

利用ParamSpec捕获后续任意参数的签名,可以让Protocol匹配以指定类型为第一个参数、后续参数任意的所有函数:

from typing import Protocol, TypeVar, Dict, Any, ParamSpec

T = TypeVar("T", covariant=True)
P = ParamSpec("P")

class Func(Protocol[T]):
    def __call__(self, ctx: Dict[Any, Any], *args: P.args, **kwargs: P.kwargs) -> T:
        pass

# 测试用例
def f(ctx: Dict[Any, Any]) -> str:
    return "hello"

def ff(ctx: Dict[Any, Any], x: int) -> str:
    return "hello"

def fff(ctx: Dict[Any, Any], x: int = 0) -> str:
    return "hello"

def ffff(x: int) -> str:
    return "hello"

a: Func[str] = f    # ✅ mypy无报错
b: Func[str] = ff   # ✅ mypy无报错
c: Func[str] = fff  # ✅ mypy无报错
d: Func[str] = ffff # ❌ mypy报错:类型不兼容,符合预期

方法二:重载Protocol的__call__方法(兼容旧版本Python)

通过给Protocol定义多个__call__重载,覆盖所有可能的参数组合场景:

from typing import Protocol, TypeVar, Dict, Any, overload

T = TypeVar("T", covariant=True)

class Func(Protocol[T]):
    @overload
    def __call__(self, ctx: Dict[Any, Any]) -> T:
        ...
    @overload
    def __call__(self, ctx: Dict[Any, Any], *args: Any) -> T:
        ...
    @overload
    def __call__(self, ctx: Dict[Any, Any], **kwargs: Any) -> T:
        ...
    @overload
    def __call__(self, ctx: Dict[Any, Any], *args: Any, **kwargs: Any) -> T:
        ...
    # 基础实现(仅用于Protocol定义,无需实际逻辑)
    def __call__(self, ctx: Dict[Any, Any], *args: Any, **kwargs: Any) -> T:
        pass

# 测试用例同上,效果一致

验证接收函数

定义接收Func类型参数的函数时,mypy会自动校验传入的函数是否符合要求:

def accept_func(func: Func[str]) -> None:
    pass

accept_func(f)    # ✅ 类型校验通过
accept_func(ff)   # ✅ 类型校验通过
accept_func(fff)  # ✅ 类型校验通过
accept_func(ffff) # ❌ mypy报错:参数类型不匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:12:31