Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type hint for nested dict

The kind of data structure I parse in my Python script is a json file which, after json.load(file_handle), is of type <class 'dict'>. So far so good. Now for a function using it as an input argument, I want a type hint for the parsed json. I read in the typing documentation, that for dicts as arguments, I should use Mapping[key_type, value_type]:

from typing import Mapping

def foo(json_data: Mapping[str, str]) -> None:
    ...

The json I parse has str-type keys and str-type values, but more often than not, its structure is highly recursive. Hence a value is more likely to be a dict with str keys and even such dicts as values. It is very nested, until, at the deepest level, the last dict finally has str keys and str values.

So how do I represent this data structure more precisely? I was thinking something, along the lines of this question, that it might be:

Union[Mapping[str, str], Mapping[str, Mapping]]

But it does seem to represent only one level of recursion. Is there a better way to type-hint this?

like image 325
Zababa Avatar asked Oct 15 '19 18:10

Zababa


1 Answers

simple dicts

you can simply use Mapping[K, V] as the value for another Mapping. let's say your json looks like this:

{
   "person_1": {"money": 1000},
   "person_2": {"money": 1000}
}

in this case you can use a type hint that looks like this:

Mapping[str, Mapping[str, int]]

harder dicts

but let's say you have something more complex, like this:

{
    "person_1": {
        "money": 1000,
        "job": "coder",
    }
}

how could you type hint this then? you can use Union (from typing) to do something like this:

Mapping[str, Mapping[str, Union[str, int]]]

but now we would run into a problem with tools like mypy thinking that our_dict["person_1"]["job"] has the type Union[str, int]

well it is not wrong, that is what we told it after all. something that could help here is TypedDict from typing_extensions.

from typing_extensions import TypedDict

class Person(TypedDict):
    money: int
    job: str

# type hint you would use in your function:
Mapping[str, Person]

NOTE: in python 3.8 TypedDict is part of typing

like image 165
vivax Avatar answered Oct 01 '22 05:10

vivax