为什么Mypy会产生这个令人困惑的typechecking错误?

问题描述 投票:0回答:1

为什么在下面 test not typecheck (with Mypy 0.780)?

from typing import Iterator, Tuple

xs: Iterator[int] = (i for i in (1,2,3))
ys: Iterator[int] = (i for i in (1,2,3))
xys: Iterator[Tuple[int,int]] = zip(*(xs,ys))

test: Tuple[int,int,int] = tuple(map(sum, xys))

的错误信息。

错误。赋值中的不兼容类型(表达式的类型为 "Tuple[Union[_T,int],...]",变量的类型为 "Tuple[int,int,int]")。

意见:转为 Tuple[int, ...] 删除该错误。

评论。我觉得这比以下情况更令人惊讶 test: Tuple[int,int,int] = tuple(range(3)) 到 typecheck (错误信息更容易理解),但也许是同一个根本问题:长度推理。

EDIT:

对于@MisterMiyagi的第二条评论,请考虑以下内容,它也会产生同样的错误,但显然可以推断长度。

xss: Tuple[Tuple[int,int,int], ...] = tuple((1,2,3) for _ in range(10))
test: Tuple[int,int,int] = tuple(map(sum, zip(*xss)))
python-3.x typechecking mypy
1个回答
1
投票

Python的类型系统一般不表达项数。Tuple 是唯一的例外;使用 任何类型 Tuple 不能表达项目计数,因此放弃了这种信息。简而言之,没有长度可以推断,因为Python的类型系统不知道这样的事情。

具体来说,无论是 mapzip 归于 Iterator[...] (如 签章). 任何之前的项目计数信息都会被丢弃。中间类型翻译可以用mypy的 reveal_type:

xss: Iterator[Tuple[int,int,int]] = ((1,2,3) for _ in range(10))
test: Tuple[int,int,int] = tuple(map(sum, zip(*xss)))
reveal_type(zip(*xss))       # note: Revealed type is 'typing.Iterator[builtins.tuple[Any]]'
reveal_type(map(sum, *xss))  # note: Revealed type is 'typing.Iterator[Union[_T`-1, builtins.int]]'

虽然人们可以 原则上 在迭代器之间传播项目计数,这在一般的静态类型检查中是不可靠的。基本的问题是,一个任意迭代器是一次性使用的:一个"n 大小 Iterator"变成了一个"n-1 大小 Iterator在一个迭代步骤后的""和一个"0 大小 Iterator"用完后。

因此,一个变量的类型持有一个"n 大小 Iterator"就得根据使用情况而改变。

a: Iterator[int] = iter((1, 2))
# a is "2 size Iterator"
b = tuple(a)
# a is "0 size Iterator"
c = tuple(a)
© www.soinside.com 2019 - 2024. All rights reserved.