Can someone explain why this code, while valid, makes the mypy static analyser complain in multiple ways:
ranges = dict() ranges['max'] = 0 ranges['services'] = [] ranges['services'].append('a')
Namely:
error: Incompatible types in assignment (expression has type "List[<nothing>]", target has type "int") error: "int" has no attribute "append"
If I simply add a type hint to the initial variable of ranges: dict = dict()
it works fine.
I am confused about why the static analyser can’t work this out by itself, especially as I am using the dict
keyword to initialise the dict in the first instance.
Advertisement
Answer
Dictionaries are usually used as keyed collections, the most important operation being to look up the value associated with an arbitrary key. Normally in a dictionary every key has the same type, and every value has the same type; if the values are heterogeneous then the expression ranges[key]
wouldn’t necessarily have a particular type (though you could represent it as a union).
In your code, the static analyser is trying to infer the type of your dictionary. The type it expects is of the form Dict[K, V]
where K
and V
are yet to be determined. The first assignment ranges['max'] = 0
gives information about both unknowns: K
seems to be str
and V
seems to be int
. So at this point, ranges
is inferred as type Dict[str, int]
.
The next two lines then give errors, because an empty list can’t be used as a value in a Dict[str, int]
, and values from a Dict[str, int]
don’t have an append
method.
The explicit type annotation ranges: dict = dict()
overrules the default behaviour by specifying that this is a heterogeneous dictionary, so that the values don’t all have to have the same type. Given that information, the static analyser doesn’t assume that because one of the values is an int
that they all have to be int
s.