mypy
mypy copied to clipboard
Tuple-like Sequence
There are situations where a variable can be either a list or a tuple (or more generally, a sequence), but it is used/unpacked in a tuple-like way. That is, the length is fixed and types are possibly heterogeneous. A practical example of this is mpi4py's buffer specifications.
I don't believe it's possible to express a fixed-length heterogeneous sequence without using Tuple
and forcing a specific type/inheritance. It'd be useful to have an abstract type that expresses tuple semantics without the inheritance bounds. So the analogy is roughly: List
is to Sequence
as Tuple
is to FixedSequence
(or whatever name we choose).
def foo(x: FixedSequence[int, str]) -> int:
return x[0]
foo((0, ''))
foo([0, ''])
Currently I think it's necessary to do Sequence[Union[int, str]]
and this loses both the fixed length and the ordering of the elements in the sequence.
I've encountered cases where something like this would have been useful.
A possible implementation would generalize the internal TupleType
type to support other tuple-like types, with different fallback types. List expression type inference should also be modified to look for these new types in the type context.
The priority seems pretty low right now, however. If somebody writes a PEP draft about this feature and it gains some interest from the community, we'd likely increase the priority.
Python 3.9's Annotated
gets us closer to the fixed-length part. Something like:
from collections.abc import Sequence
from typing import Annotated, TypeAlias
TTwoItem: TypeAlias = Annotated[Sequence[int], 2]
some_list: TTwoItem = [1, 2]
some_tuple: TTwoItem = (1, 2)
some_incorrect_tuple: TTwoItem = (1, 2, 3) # A possible future mypy would error here
Note this would not accommodate the type heterogeneity aspect of this request.
TTwoItem: TypeAlias = Annotated[Sequence[int], 2]
Could also be used to specify a range of valid lengths, e.g.
TTwoOrThreeInts: TypeAlias = Annotated[Sequence[int], range(2, 4)]
would specify a sequence with either 2 or 3 items.
Just chiming in that I'd love to be able to have code like this pass type checks, and I think this request would be perfect for my case:
dict([[1,2]))
dict(["aa", "gg", "tt", "cc"])