Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mypy Cannot infer type argument. Difference between List and Iterable

T = TypeVar("T", bound=Union[str, int])


def connect_lists(list_1: list[T], list_2: list[T]) -> list[T]:
    out: list[T] = []
    out.extend(list_1)
    out.extend(list_2)
    return out

connect_lists([1, 2], ["a", "b"])

mypy:

error: Cannot infer type argument 1 of "connect_lists" [misc]

T = TypeVar("T", bound=Union[str, int])


def connect_lists(list_1: Iterable[T], list_2: Iterable[T]) -> list[T]:
    out: list[T] = []
    out.extend(list_1)
    out.extend(list_2)
    return out

connect_lists([1, 2], ["a", "b"])

Now mypy doesn't raise an error.

What is the difference between List and Iterable in this case?

like image 499
Artem Avatar asked Jul 01 '26 03:07

Artem


1 Answers

Iterable is covariant - an Iterable[int] is also an Iterable[int|str].

list is not covariant - a list[int] is not a list[int|str], because you can add strings to a list[int|str], which you can't do with a list[int].

mypy infers the types of [1, 2] and ["a", "b"] as list[int] and list[str] respectively. With the first definition of connect_objects, there is no choice of T that will make the call valid. But with the second definition, a list[int] is an Iterable[int], which is an Iterable[int|str], and a list[str] is similarly also an Iterable[int|str], so T is inferred as int|str.

I don't think there's actually a spec yet for how type inference works. There may never be such a spec. Future mypy versions might perform this inference differently, for example, performing context-sensitive inference to infer a type of list[int|str] for both input lists, making the first version of the code pass type checking.

like image 150
user2357112 supports Monica Avatar answered Jul 02 '26 15:07

user2357112 supports Monica