As of mypy 0.990, mypy finally supports recursive type annotations, using the natural syntax:

from typing import Union, Dict, List

JSONVal = Union[None, bool, str, float, int, List['JSONVal'], Dict[str, 'JSONVal']]

d: JSONVal = {'a': ['b']}

mypy output:

Success: no issues found in 1 source file

Before 0.990, this would produce an error reporting a lack of recursive type support:

$ mypy asdf.py
asdf.py:3: error: Recursive types not fully supported yet, nested types replaced with "Any"

On such versions, Dict[str, Any] would be the way to go.


You can also use mutually recursive type aliases now, so you can do things like

from typing import Union, Dict, List

JSONVal = Union[None, bool, str, float, int, 'JSONArray', 'JSONObject']
JSONArray = List[JSONVal]
JSONObject = Dict[str, JSONVal]

d: JSONObject = {'a': ['b']}
Answer from user2357112 on Stack Overflow
🌐
Medium
medium.com › @marcnealer › python-recursive-functions-extracting-data-from-javascript-json-blobs-bc11738f1228
Python Recursive Functions: Extracting data from JavaScript/JSON blobs | by Marc Nealer | Medium
August 25, 2024 - This example is not one I think you should use. There are way better ways of doing this, but it shows how recursive functions work and they can replace loops. You can see from the sequence diagram this is a straight recursive call. You should note that python has a 10,000 recursive depth limit set.
Discussions

python - How to recursively find specific key in nested JSON? - Stack Overflow
Here is a simple recursive function to collect all values from a json document for a given key. Values can be json documents as well. The corresponding values appended to search_result. def json_full_search(lookup_key, json_dict, search_result = []): if type(json_dict) == dict: for key, value ... More on stackoverflow.com
🌐 stackoverflow.com
python - After recursive search of my json object how to determine data type for looping data - Stack Overflow
I have a recursive function that examines a json object. It captures the data when I try to loop the data, it works for one but not the other. I need help determining what type of data the returne... More on stackoverflow.com
🌐 stackoverflow.com
use python recursive function to parse a json with some regulation - Stack Overflow
So your recursive evaluator only needs to handle those two cases. Most of the real work will be in translating your custom operators into something that Python understands. ... import operator def check_type(obj, type_name): #we can't just directly use `isinstance` for type checks, because ... More on stackoverflow.com
🌐 stackoverflow.com
recursion - Recursive search in json with python - Stack Overflow
instead of check on the timestamp it is possible to do that considering if the "type" is "Recursive" ? since sometimes timestamp is present even in type nothing....but for semplicity I removed it in the json example 2021-07-28T14:37:02.583Z+00:00 More on stackoverflow.com
🌐 stackoverflow.com
🌐
Stack Overflow
stackoverflow.com › questions › 75697579 › after-recursive-search-of-my-json-object-how-to-determine-data-type-for-looping
python - After recursive search of my json object how to determine data type for looping data - Stack Overflow
targetType = 'equal' def find_data(lookup_key, jsonData, search_result = []): if type(jsonData) == dict: for key, value in jsonData.items(): if targetType == 'equal' and key == lookup_key: search_result.append(value) elif targetType == 'regex' and pattern.search(key): search_result.append(value) find_data(lookup_key, value, search_result) elif type(jsonData) == list: for element in jsonData: find_data(lookup_key, element, search_result) return search_result
Top answer
1 of 1
1

I'm interpreting this question as "my injson data structure contains a series of objects that represent the components of an expression. How can I evaluate this expression and return the final result?"

The grammar of your expression language looks pretty simple: each component is either a simple value, such as "yang", or a dictionary that represents a function call. So your recursive evaluator only needs to handle those two cases. Most of the real work will be in translating your custom operators into something that Python understands.

Example implementation:

import operator

def check_type(obj, type_name):
    #we can't just directly use `isinstance` for type checks, because `isinstance("foo", "string")` doesn't understand what the second argument is supposed to represent.
    #so we need an extra layer here to convert type-looking strings into actual types.
    types_by_name = {"string": str, "int": int, "bool": bool} #add more types as desired
    return isinstance(obj, types_by_name[type_name])

operators_by_name = {
    "gte": operator.ge,
    "startswith": str.startswith,
    "type": check_type,
    #add more named functions as desired
}

def eval_json(obj):
    if isinstance(obj, dict) and "$op" in obj:
        op = operators_by_name[obj["$op"]]
        args = [eval_json(arg) for arg in obj["$params"]]
        return op(*args)
    else:
        return obj

injson = {
    "params": [
        {
            "$op": "startswith",
            "$params": ["yang", "y"]
        },
        {
            "$op": "type",
            "$params": ["yang", "string"]
        }
    ]
}
print(eval_json(injson))

Result:

True

This is the desired result, since "yang".startswith("y") >= isinstance("yang", str) also evaluates to True.

Find elsewhere
Top answer
1 of 3
1

with recursion you can do something like this:

result = []

def finditem(obj, key):
    if key in obj: result.append({"timestamp": obj[key], "text": obj['textsList'][0]['text']})
    for k, v in obj.items():
        if isinstance(v,dict):
            item = finditem(v, key)
            if item is not None:
                result.append({"timestamp": item,"text":v['textsList'][0]['text']})
        elif isinstance(v,list):
            for i in v:
                item = finditem(i, key)
                if item is not None:
                    result.append({"timestamp": item,"text": i['textsList'][0]['text']})

finditem(data, 'timestamp')
print (result)

result:

[{'timestamp': 1234567890, 'text': 'some text here 0'}, {'timestamp': 12345678901234, 'text': 'some other text 1'}, {'timestamp': 12345678901234, 'text': 'some other text 2'}]

EDIT:

result = []
def finditem(obj, key):
    if key in obj and obj[key]=='Recursive': result.append({"timestamp": obj["data"]["timestamp"],"text": obj["data"]['textsList'][0]['text']})
    for k, v in obj.items():
        if isinstance(v,dict):
            item = finditem(v, key)
            if item == 'Recursive':
                d = v['timestamp']
                result.append({"timestamp": d,"text": v['textsList'][0]['text']})
        elif isinstance(v,list):
            for list_item in v:
                item = finditem(list_item, key)
                if item == 'Recursive':
                    d = list_item['timestamp']
                    result.append({"timestamp": d,"text": list_item['textsList'][0]['text']})

finditem(data,'type')
print (result)

result:

[{'timestamp': 12345678901234, 'text': 'some other text 1'}, {'timestamp': 12345678901234, 'text': 'some other text 2'}]
2 of 3
1

You can use a recursive generator function:

def get_text(d):
   if isinstance(d, dict):
      if 'timestamp' in d:
         yield {'timestamp':d['timestamp'], 'textsList':''.join(i['text'] for i in d['textsList'])}
      for b in d.values():
         yield from get_text(b)
   elif isinstance(d, list):
      yield from [i for j in d for i in get_text(j)]

data = {'result': [{'timestamp': 1234567890, 'textsList': [{'text': 'some text here 0'}], 'otherList': [{'type': 'Nothing'}, {'type': 'Recursive', 'data': {'timestamp': 12345678901234, 'textsList': [{'text': 'some other text 1'}], 'otherList': [{'type': 'Nothing'}, {'type': 'Recursive', 'data': {'timestamp': 12345678901234, 'textsList': [{'text': 'some other text 2'}], 'otherList': []}}]}}]}]}
print(list(get_text(data)))

Output:

[{'timestamp': 1234567890, 'textsList': 'some text here 0'}, 
 {'timestamp': 12345678901234, 'textsList': 'some other text 1'}, 
 {'timestamp': 12345678901234, 'textsList': 'some other text 2'}]
🌐
Reddit
reddit.com › r/learnpython › json type in mypy.
r/learnpython on Reddit: Json Type in Mypy.
January 16, 2025 -

Hey there! I have a weird question but Im stuck for days on this.

I have quite a lot of requests done via python using the requests module.

def url_requester(url: str) -> list | ???: response=requests.request(method, payload, url, etc) if method=="get": return response.json()[0] return response.json()

Is there a proper way you type hint this function? It has being killing me, mypy says it is wrong . Thanks!

Top answer
1 of 3
3
json() returns JSON parsed as Python dictionaries and lists, so list | dict would work. That's pretty broad though, and may lead to issues down the road when reading this data, since lists and dicts have quite different interfaces. If you know exactly what shape of data is returned (which is usually the case), you would specify that instead. If it's a list of strings returned, you'd do list[str], for example. If it's a dictionary with specific keys though, look into a TypedDict. It allows you to specify the expected keys and the types of the associated values.
2 of 3
3
I vaguely recall someone telling me MyPy can now cope with recursive types. Playing with this on MyPy's playground, you can rig something together that can in theory represent JSON in a type-safe way (although not with the ability to assert things like "this array must always hold strings"). import json from collections.abc import Mapping, Sequence from typing import AnyStr, cast type JsonNull = None type JsonBool = bool type JsonNumber = int | float type JsonString = str type JsonArray = Sequence[JsonType] type JsonObject = Mapping[JsonString, JsonType] type JsonContainer = JsonArray | JsonObject type JsonType = JsonNull | JsonBool | JsonNumber | JsonString | JsonContainer def json_loads(raw: AnyStr) -> JsonContainer: return cast(JsonContainer, json.loads(raw)) This will at least force you to validate that types are specific JSON-compatible values prior to doing things with it. I may have forgotten some edge cases, and yes, this is overengineered IMHO. Generally if you care about types to this extent, you'd be better off using something like Pydantic and converting your requests responses to a proper typed object before returning it where possible.
🌐
Python.org
discuss.python.org › ideas
Generic `typing.ForwardRef` to support generic recursive types - Ideas - Discussions on Python.org
October 21, 2022 - E.g.: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] Recursive types need to use ForwardRefs at the right-hand side to reference the type alias before assignment.
🌐
Sling Academy
slingacademy.com › article › recursive-types-in-modern-python-a-practical-guide
Recursive Types in Modern Python: A Practical Guide - Sling Academy
Recursive types are not just academic; they have practical applications in areas like data processing, computational linguistics, and more. For example, parsing nested structures like JSON or XML can be elegantly achieved with recursive types.
🌐
Reddit
reddit.com › r/learnpython › converting json into dictionary and recursion
r/learnpython on Reddit: converting JSON into dictionary and recursion
November 13, 2022 -

I am studying trying to self teach python with an online course and I am stuck on a question I would like some help with, the question is:

"George runs a company. He manages James and Jamila, who each have a small team to manage. In James' team are Jill and Jenny. In Jamila's team are Jewel, Jasmine and Jeremy. Create a JSON object in a string variable called company where each item has a name field and a field called manages which contains an array of the people managed by that person. If a person does not manage anybody, they have no field called manages. Then convert the JSON string to a dictionary in a variable called company_dict.

Finally, write a recursive function that accepts the dictionary as an argument and lists each person and their level in the organisation, so that George is at level 1, James and Jamila are at 2, and so on. Call the function and print the result. It should look like this: George is at level 1 James is at level 2 Jill is at level 3 Jenny is at level 3 Jamila is at level 2 Jewel is at level 3 Jasmine is at level 3 Jeremey is at level 3 The function can either return a string, which you print after it has been called, or it can print its results as it runs and return nothing."

🌐
GitHub
github.com › python › mypy › issues › 13693
Recursive Generic Type Support · Issue #13693 · python/mypy
September 20, 2022 - Bug Report In: #731 #13297 (not released yet in v0.971) We now support recursive type hints, such as: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] But ...
Author: python
🌐
Medium
medium.com › @n0mn0m › recursive-search-with-python-ceab8c8d1eb3
Recursive Search with Python. Recently I received from JSON like data… | by Alexander Hagerman | Medium
October 31, 2021 - Luckily Python has acopy module in the standard library to help with this scenario. The function below represents my final result. This worked well on the sample data, and eventually was used on PySpark RDDs to process hundreds of millions of structures quickly. import copy from future.utils import iteritems def search ( input , row_base , search_key , results ): """ A search function to help transform nested JSON like objects into tabular rows.
🌐
PyPI
pypi.org › project › python-easy-json
python-easy-json · PyPI
python-easy-json is a recursive JSON to python object deserializer with support for defining data models and casting data to python using type hint annotations.
      » pip install python-easy-json
    
Published: Jan 17, 2026
Version: 1.2.4
🌐
GitHub
gist.github.com › 066ceacbcf1f05e8be135ab20ac7ebdd
Python 3 - Traverse json recursively and capitalize first letters of each key. · GitHub
Python 3 - Traverse json recursively and capitalize first letters of each key. - capitalize_json.py
🌐
Chopin's blog
chopin.hashnode.dev › validating-recursive-jsons-using-json-schema-in-python
Validating recursive JSONs using JSON Schema in Python
July 30, 2024 - JSON Schema seems to be an industry standard for this sort of stuff and they have a Python package jsonschema! JSON Schema facilitates many things, one of which is validation. >>> from jsonschema import validate >>> # A sample schema, like what we'd get from json.load() >>> schema = { ... "type" : "object", ...
🌐
Ship That Code
shipthatcode.com › home › courses › build your own json parser › recursive structures
Shipthatcode
JSON's grammar is recursive with no depth bound: a value may contain values, ad infinitum. Your parser mirrors that with mutual recursion — parseValue → parseArray → parseValue — which is elegant right up until someone feeds you: ... ...
🌐
GitHub
github.com › kevklash › JSON_recursion
GitHub - kevklash/JSON_recursion: Recursive function written in Python
Recursive function written in Python. Contribute to kevklash/JSON_recursion development by creating an account on GitHub.
Author: kevklash