Skip to content
Advertisement

Static type analysis with Python dicts

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 ints.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement