在下面的示例中,如何正确注释sum_two
函数的返回类型?
from typing import Any, TypeVar
T = TypeVar('T')
S = TypeVar('S')
def sum_two(first: T, second: S):
return first + second
假设__add__
运算符已正确注释将传递给此函数的所有可能参数,有没有某种方法可以将返回类型表示为在类型为T
和S
的对象上调用__add__
的返回类型?
我想避免使用打字的overload
装饰器来识别所有可能的情况,因为可能有几十个案例。
理论上,您可以通过使first
成为通用协议来完成他的一部分,该协议允许您"捕获"__add__
的返回类型。例如:
# If you are using Python 3.7 or earlier, you'll need to pip-install
# the typing_extensions module and import Protocol from there.
from typing import TypeVar, Protocol, Generic
TOther = TypeVar('TOther', contravariant=True)
TSum = TypeVar('TSum', covariant=True)
class SupportsAdd(Protocol, Generic[TOther, TSum]):
def __add__(self, other: TOther) -> TSum: ...
然后,您可以执行以下操作:
S = TypeVar('S')
R = TypeVar('R')
# Due to how we defined the protocol, R will correspond to the
# return type of `__add__`.
def sum_two(first: SupportsAdd[S, R], second: S) -> R:
return first + second
# Type checks
reveal_type(sum_two("foo", "bar")) # Revealed type is str
reveal_type(sum_two(1, 2)) # Revealed type is int
reveal_type(sum_two(1.0, 2)) # Revealed type is float
# Does not type check, since float's __radd__ is ignored
sum_two(1, 2.0)
class Custom:
def __add__(self, x: int) -> int:
return x
# Type checks
reveal_type(sum_two(Custom(), 3)) # Revealed type is int
# Does not type check
reveal_type(sum_two(Custom(), "bad"))
但是,此方法确实有一些限制:
- 它不处理"第一"中没有匹配
__add__
的情况,但在"第二"中具有匹配__radd__
。 - 如果您修改自定义
__add__
则可能会得到一些奇怪的结果,这是重载。我认为至少 mypy 目前有一个错误,它不知道如何正确处理涉及子类型和重载的复杂情况。