总和的类型是什么



我想表示第一个参数是一个"列表";并且结果具有与第二参数相同的类型。

这个mysum(即不是标准的libsum(应该与int/foat/str/list以及任何其他支持+=的类型同样适用。

天真:

def mysum(lst: list[T], start: T) -> T:
x = start
for item in lst:
x += item
return x    

其产生:

(dev311) go|c:srvtmp> mypy sumtype.py
sumtype.py:26: error: Unsupported left operand type for + ("T")
sumtype.py:35: error: Cannot infer type argument 1 of "mysum"
Found 2 errors in 1 file (checked 1 source file)

第二次尝试:

from typing import Iterable, Protocol, TypeVar
T = TypeVar('T')
class Addable(Protocol[T]):
def __add__(self, other: T) -> T:
...
class RAddable(Protocol[T]):
def __radd__(self, other: T) -> T:
...
def mysum(lst: Iterable[Addable|RAddable], start: Addable) -> Addable:
x = start
for item in lst:
x += item
return x

然而,这并没有对";列表";项,并且开始是相同的类型,因此此类型检查:

class Foo:
def __radd__(self, other: int) -> int:
return other + 42

mysum([Foo()], [])  # <=== should ideally fail since Foo() and [] are not the same type

并在运行时出现类型错误而失败:

(dev311) go|c:srvtmp> python sumtype.py
Traceback (most recent call last):
File "c:srvtmpsumtype.py", line 27, in <module>
mysum([Foo()], [])
File "c:srvtmpsumtype.py", line 18, in mysum
x += item
File "c:srvtmpsumtype.py", line 24, in __radd__
return other + 42
~~~~~~^~~~
TypeError: can only concatenate list (not "int") to list

我假设对泛型函数进行类型注释不会这么困难,那么我缺少什么。。?

您可以将泛型类型绑定到支持__add__的协议:

类型变量可以绑定到具体类型、抽象类型(ABC或协议(,甚至类型的联合

from typing import TypeVar, Protocol
T = TypeVar('T', bound='Addable')
class Addable(Protocol):
def __add__(self: T, other: T) -> T:
...
def mysum(lst: list[T], start: T) -> T:
x = start
for item in lst:
x += item
return x

演示:https://mypy-play.net/?gist=ecf4031f21fb81e75d6e6f75d16f3911

我想您在第二次尝试时忘记了将类型参数传递给(R)Addable

from typing import Iterable, Protocol, TypeVar
T = TypeVar('T')
class Addable(Protocol[T]):
def __add__(self: T, other: T) -> T:
...
class RAddable(Protocol[T]):
def __radd__(self: T, other: T) -> T:
...
def mysum(lst: Iterable[Addable[T]|RAddable[T]], start: Addable[T]) -> T:
x = start
for item in lst:
x += item
return x

但这也行不通。使用@blhsing建议的有界TypeVar比这更优雅、更直观。

mypy中唯一可以在没有绑定TypeVar:的情况下获得的工作示例

from typing import Iterable, Protocol, TypeVar
T = TypeVar('T')
class Addable(Protocol[T]):
def __add__(self: T, other: T) -> T: ...
def mysum(lst: Iterable[Addable[T]], start: T) -> T:
x = start
for item in lst:
x = item + x
return x
print(mysum(['a'], 'b'))

str不是mypy中的RAddable[T]int正常:

from typing import Iterable, Protocol, TypeVar
T = TypeVar('T')
class RAddable(Protocol[T]):
def __radd__(self: T, other: T) -> T: ...
def mysum(lst: Iterable[RAddable[T]], start: T) -> T:
x = start
for item in lst:
x += item
return x
print(mysum([1], 2))

相关内容

  • 没有找到相关文章

最新更新