You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Failure to correctly infer tuple type through zip #8454
error: Argument 1 to "list" has incompatible type "Tuple[object, object]"; expected "Iterable[Union[str, int]]"
Explicitly typing the tuple as follows removes the error: vals: Tuple[Tuple[str, int], ...] = (("zz", 1), ("yyy", 8))
Interesting, explicitly typing the tuple and the nested tuples does not remove the error: vals: Tuple[Tuple[str, int], Tuple[str, int]] = (("zz", 1), ("yyy", 8))
produces the same error above when no type hint is provided.
As you can see, it treats its input arguments as Iterable[T] (a homogenous iterable). When mypy tries to figure out what the most appropriate T for Tuple[str, int] is, it correctly infers object (the common baseclass of str and int). Hence:
~/delete λ cat test37.py
vals = (("zz", 1), ("yyy", 8))
reveal_type(vals)
reveal_type(zip(*vals))
~/delete λ mypy test37.py
test37.py:2: note: Revealed type is 'Tuple[Tuple[builtins.str, builtins.int], Tuple[builtins.str, builtins.int]]'
test37.py:3: note: Revealed type is 'typing.Iterator[Tuple[builtins.object*, builtins.object*]]'
You can also see from how zip is typed at the typeshed link that if you pass in enough arguments or splat something of length that's unknown to the type system, it doesn't list out the typevars and instead gives up and returns Any.
"Something of unknown length to the type system" explains why your explicit type annotation works (would also work if you typed it as Iterable or made the thing a list).
"Pass in enough arguments" explains your second comment.
The output of something like zip(*[("a", 1), ("b", 2)]) is an Iterator with the first item Tuple[str] and the second item Tuple[int] and there isn't really a good way to type that.
We could lie in typeshed for a couple of these, maybe with something like def zip(*iter: Tuple[_T1, _T2]) -> Tuple[Tuple[_T1, ...], Tuple[_T2, ...]]
Yes, properly typing this would require heterogeneous iterables, it is unlikely it will be supported in foreseeable future. You can however propose the quick fix (adding few extra overloads) on typeshed tracker, as suggested.
Activity
JonathanShor commentedon Feb 28, 2020
Might be relevant, but when
valsis 6 or more entries long, the error is not produced. Mypy is fine with the following.vals = (("zz", 1), ("yyy", 2), ("xxx", 3), ("w", 4), ("v", 5), ("u", 6))EXAMPLE: Dict[str, List[Union[str, int]]] = { k: list(val) for k, val in zip(["A", "B"], zip(*vals)) }...
>>> EXAMPLE{'A': ['zz', 'yyy', 'xxx', 'w', 'v', 'u'], 'B': [1, 2, 3, 4, 5, 6]}hauntsaninja commentedon Mar 1, 2020
This is basically because of how
zipis typed in typeshed: https://github.com/python/typeshed/blob/master/stdlib/2and3/builtins.pyi#L1446As you can see, it treats its input arguments as
Iterable[T](a homogenous iterable). When mypy tries to figure out what the most appropriateTforTuple[str, int]is, it correctly infersobject(the common baseclass ofstrandint). Hence:You can also see from how
zipis typed at the typeshed link that if you pass in enough arguments or splat something of length that's unknown to the type system, it doesn't list out the typevars and instead gives up and returns Any."Something of unknown length to the type system" explains why your explicit type annotation works (would also work if you typed it as Iterable or made the thing a list).
"Pass in enough arguments" explains your second comment.
The output of something like
zip(*[("a", 1), ("b", 2)])is anIteratorwith the first itemTuple[str]and the second itemTuple[int]and there isn't really a good way to type that.We could lie in typeshed for a couple of these, maybe with something like
def zip(*iter: Tuple[_T1, _T2]) -> Tuple[Tuple[_T1, ...], Tuple[_T2, ...]]hauntsaninja commentedon Mar 1, 2020
So maybe we should move this issue to typeshed and see if people have objections to that lie^
ilevkivskyi commentedon Mar 6, 2020
Yes, properly typing this would require heterogeneous iterables, it is unlikely it will be supported in foreseeable future. You can however propose the quick fix (adding few extra overloads) on typeshed tracker, as suggested.
zip: add some overloads for heterogeneous tuples
zip: add some overloads for heterogeneous tuples (#3830)
zip: add some overloads for heterogeneous tuples (python#3830)