我想编写以下重载的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()
parse_as()
的目标是尝试将输入字节解析为给定类型,如果成功,则返回给定类型的值。然而,这给出了以下 mypy 错误:
error: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader
是否有任何方法来表达
parse_as()
的类型?
旁白:在我的特殊情况下,所有
TypeVar
与其
bound
共享相同的类,如果这很重要。
你遇到的错误信息 "Overloaded function signature 2 will never be matched" 是因为 MyPy 认为你的第二个
@overload
永远不会被调用。这是因为第一个
@overload
的类型提示比第二个更宽泛,可以匹配任何能匹配第二个
@overload
的情况。
具体来说,
type[_T1] | type[_T2]
可以匹配任何
type[_T1] | type[_T2] | type[_T3]
的情况,因为
_T1
、
_T2
、
_T3
都是 TypeVar,可以代表任何类型。
为了解决这个问题,你需要让你的
@overload
函数签名更加具体,避免出现这种重叠的情况。以下是一些可能的解决方案:
1. 使用不同的参数类型:
与其使用联合类型,不如为每种类型组合定义一个单独的
@overload
函数。例如:
from typing import Any, TypeVar, overload
_T1 = TypeVar('_T1')
_T2 = TypeVar('_T2')
_T3 = TypeVar('_T3')
@overload
def parse_as(ty: type[_T1], s: bytes) -> _T1:
...
@overload
def parse_as(ty: type[_T2], s: bytes) -> _T2:
...
@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()
这样,每个
@overload
函数都有一个独特的类型签名,可以避免 MyPy 出现混淆。
2. 使用 Literal 类型:
你可以使用
typing.Literal
来指定更精确的类型,例如:
from typing import Any, TypeVar, overload, Literal
_T = TypeVar('_T')
@overload
def parse_as(ty: Literal[int, str], s: bytes) -> _T:
...
@overload
def parse_as(ty: type[_T], s: bytes) -> _T:
...
def parse_as(ty: Any, s: bytes) -> Any:
raise NotImplementedError()
这样,第一个
@overload
函数只会在
ty
是
int
或
str
类型时被调用。
3. 重新思考你的设计:
有时候,出现这种类型重叠的情况,可能是因为你的函数设计过于复杂。你可以考虑将
parse_as
函数拆分成多个更小、更具体的函数,每个函数处理一种特定的类型。
需要根据你的具体需求选择最合适的解决方案。
标签:python,python-typing,mypy From: 78842293