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
相关产品推荐
相关产品推荐

