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

Python 3.10子类化带可变关键字参数的泛型类遇mypy报错求方案

解决mypy报错“Unpack is only valid in a variadic position”的替代方案

你的代码报错核心是:ParamSpec用于定义函数参数签名的泛型约束,而TypedDict是描述字典结构的类型,直接将Unpack(Inputs)作为A的泛型参数(ParamSpec的位置)不符合mypy的语法规则,Unpack仅允许在可变参数(比如**kwargs: Unpack[TD])这类场景中使用。

以下是几种不依赖Callable的替代实现方式:

方案一:子类重载func方法,明确参数类型

直接在子类中重写func,指定对应参数的类型,既保留父类逻辑,又满足类型检查:

from typing import Generic, TypeVar, ParamSpec, TypedDict

P = ParamSpec("P")
T = TypeVar("T")

class A(Generic[P]):
    def func(self, *args: P.args, **kwargs: P.kwargs) -> int:
        print(args)
        print(kwargs)
        return 2

class Inputs(TypedDict):
    arg1: int
    arg2: str

class B(A):
    def func(self, *, arg1: int, arg2: str) -> int:
        return super().func(arg1=arg1, arg2=arg2)

B().func(arg1=1, arg2="Hello")  # mypy检查无报错

方案二:用TypeVar绑定TypedDict,父类直接约束kwargs类型

将父类的泛型参数改为绑定TypedDict的TypeVar,直接标注kwargs的类型,无需重载方法:

from typing import Generic, TypeVar, TypedDict

# 定义绑定TypedDict的TypeVar
TD = TypeVar("TD", bound=TypedDict)

class A(Generic[TD]):
    def func(self, **kwargs: TD) -> int:
        print(kwargs)
        return 2

class Inputs(TypedDict):
    arg1: int
    arg2: str

class B(A[Inputs]):
    pass

B().func(arg1=1, arg2="Hello")  # mypy检查无报错

这个方案的优势是复用父类逻辑,代码简洁,同时能严格约束func的关键字参数结构。

方案三:用Protocol定义方法签名约束

通过Protocol定义func的参数签名,让子类遵循该协议,兼顾继承和类型约束:

from typing import Protocol, TypedDict

class Inputs(TypedDict):
    arg1: int
    arg2: str

# 定义方法签名协议
class FuncProtocol(Protocol):
    def func(self, *, arg1: int, arg2: str) -> int:
        ...

class A:
    def func(self, **kwargs) -> int:
        print(kwargs)
        return 2

# 同时继承A和遵循FuncProtocol
class B(A, FuncProtocol):
    pass

B().func(arg1=1, arg2="Hello")  # mypy检查无报错

这种方式利用Python的结构子类型特性,无需修改父类泛型,就能对子类的方法签名做严格约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 15:10:13