Python中@overload用Union类型导致签名重叠错误,如何正确定义类型?
解决parse_as重载函数的mypy类型错误
我尝试编写一个名为parse_as的Python函数,用于将输入字节解析为指定类型,代码如下:
from typing import Any, TypeVar, overload _T1 = TypeVar('_T1') _T2 = TypeVar('_T2') _T3 = TypeVar('_T3') @overload def parse_as(ty: type[_T1] | type[_T2], s: bytes) -> _T1 | _T2: ... @overload def parse_as(ty: type[_T1] | type[_T2] | type[_T3], s: bytes) -> _T1 | _T2 | _T3: ... def parse_as(ty: Any, s: bytes) -> Any: raise NotImplementedError()
运行mypy时出现错误:
error: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader
请问该如何正确表达这个函数的类型?另外,所有TypeVar均绑定同一类,这会有影响吗?
错误原因
mypy报错是因为联合类型的匹配逻辑:type[_T1] | type[_T2]这个类型实际上比type[_T1] | type[_T2] | type[_T3]更宽泛——Python的联合类型是无序且可扩展的,任何能匹配第二个重载参数的输入,都能被第一个重载的参数类型接受,因此第二个重载永远不会被触发。
正确的类型写法
不需要为不同数量的类型选项编写多个重载,而是使用可变长度类型变量元组(TypeVarTuple + Unpack)来支持任意数量的目标类型,这样既简洁又能覆盖所有情况:
from typing import Any, TypeVarTuple, Unpack, overload # 定义可变长度的类型变量元组 _Ts = TypeVarTuple('_Ts') @overload def parse_as(ty: type[Unpack[_Ts]], s: bytes) -> Unpack[_Ts]: ... def parse_as(ty: Any, s: bytes) -> Any: raise NotImplementedError()
如果你的需求是允许传入单个类型或多个类型的元组(比如parse_as((int, str), b'123')),可以调整重载为:
from typing import Any, TypeVar, TypeVarTuple, Unpack, overload _T = TypeVar('_T') _Ts = TypeVarTuple('_Ts') @overload def parse_as(ty: type[_T], s: bytes) -> _T: ... @overload def parse_as(ty: tuple[type[Unpack[_Ts]]], s: bytes) -> Unpack[_Ts]: ... def parse_as(ty: Any, s: bytes) -> Any: raise NotImplementedError()
关于TypeVar绑定同一类的影响
如果所有TypeVar都绑定了同一个类(比如_T1 = TypeVar('_T1', bound=MyClass)),只会限制可解析的类型必须是该类的子类,不会影响重载的正确性。只要按照上述方式调整类型定义,mypy就能正确识别类型约束。
内容的提问来源于stack exchange,提问作者tibbe
相关产品推荐
相关产品推荐

