Skip to content Skip to sidebar Skip to footer

Why Does Mypy Infer The Common Base Type Instead Of The Union Of All Contained Types?

When iterating over a heterogeneous sequence (containing elements of type T1 and T2, say), mypy infers the target variable to have type object (or another base type shared between

Solution 1:

Picking the common base class of the list elements (picking the join) instead of taking the union of the elements is a deliberate design choice that mypy made.

In short, the problem is that no matter which of the two solutions you pick, you'll always end up with edge cases that end up being inconvenient for somebody. For example, inferring the union would be inconvenient in cases like the following where you want to modify or add to the list, instead of only reading it:

classParent: passclassChild1(Parent): passclassChild2(Parent): passclassChild3(Parent): pass# If foo is inferred to be type List[Union[Child1, Child2]] instead of List[Parent]
foo = [Child1(), Child2()]

# ...then this will fail with a type error, which is annoying.
foo.append(Child3())

It's possible that mypy could perhaps try applying some clever heuristic to determine whether it should infer a join or a union, but that'll probably end up being fairly confusing and difficult to predict for end-users.

This is also a pretty easy issue to work around in practice -- for example, you could just add an explicit annotation to your variable:

from typing importUnion, Sized, List# If you want the union
xs: List[Union[int, str]] = [1, "1"]

# If you want any object with the `__len__` method
ys: List[Sized] = [1, "1"]

So given these two factors, implementing some fancy heuristic or switching to inferring unions entirely (and disrupting a lot of existing code) doesn't really seem worth it.

Post a Comment for "Why Does Mypy Infer The Common Base Type Instead Of The Union Of All Contained Types?"