Constructing JSON with Python Dictionaries and Lists
json.loads() transforms a JSON string into a Python data structure by parsing the text and building corresponding lists, dictionaries, and primitive values.
Try it: Parsing JSON into Python
How json.loads() reads JSON text token by token and builds Python dicts, lists, strings, numbers, True/False and None, how an access path like data["users"][0]["name"] walks that structure, and what json.dumps() writes back.
How it works
- The scanner reads the next token: a brace or bracket, a string in double quotes, a number, true / false / null, or a ',' / ':' delimiter.
- '{' starts a Python dict and '[' a list; both are pushed on a parse stack until their closing '}' or ']'.
- Inside a dict every key must be a double-quoted string followed by ':' and a value; items are separated by ','.
- Anything else stops the parse with JSONDecodeError, reporting the message, line, column and character position.
- The access path is applied one subscript at a time: dicts take keys (KeyError if missing), lists take integer indexes (IndexError if out of range).
- json.dumps() turns the Python objects back into JSON text (True → true, None → null), optionally indented.
Default run (43 steps): json.loads() receives 105 characters of text. The scanner starts at char 0 and reads one token at a time. … json.dumps(data, indent=2) turns the Python objects back into JSON text (171 characters): True → true, None → null, and strings get double quotes.
Simplified: Written from scratch to match CPython 3.12's json module (messages and positions checked against it); input is limited to 400 characters and 24 nesting levels, and the access path accepts only ["key"] and [index] subscripts. Python 3.13 reports a trailing comma in an object with a different message.
Loading the simulation…
From Text to Structure
A JSON document often arrives as text, but your Python program needs a usable data structure. The function json.loads() parses a JSON string and returns a new Python object built from the structure represented in that text. The original string is unchanged, so assign the returned object to a variable before trying to access its contents.
The Container Relationship
The shape of the JSON determines the shape of the returned Python data. A JSON object becomes a Python dictionary, and a JSON array becomes a Python list. Nested objects and arrays remain nested after parsing. Primitive values remain values inside those containers. This means the brackets and braces in the original text provide a map for understanding the Python structure that json.loads() creates.
A User List Step by Step
import json
data = '[{"id": 1, "x": 10, "name": "Ari"}, {"id": 2, "x": 20, "name": "Bea"}]'
info = json.loads(data)
print(len(info))
print(info[0]['name'])
print(info[1]['x'])- 1The outer square brackets in data indicate a list.
- 2The two brace-delimited sections inside the list indicate two dictionary-like JSON objects.
- 3After parsing, info is a list containing two dictionaries.
- 4info[0] selects the first dictionary, and ['name'] selects its name field.
- 5info[1] selects the second dictionary, and ['x'] selects its x field.
- data is a JSON string.
json.loads(data)returns the parsed Python structure and assigns it to info.- The outer square brackets represent a list, so
len(info)counts two elements. - Each list element is a dictionary, so info[0]['name'] uses a list index followed by a dictionary key.
- The second dictionary's x field is accessed with info[1]['x'].
2
Ari
20Reading the Nested Shape
Accessing parsed JSON is a structure-tracing task. At every level, first determine what kind of container you are holding. If the current value is a list, use an index such as [0] or [1]. If it is a dictionary, use a key such as ['name'] or ['x']. In the user example, the path info[0]['name'] means: start with the top-level list, select its first element, then select the name field from the resulting dictionary.
Tracing a Deeper Path
viewerThe access path crosses several levels. parsed is a dictionary, so ['users'] selects its users field. That field contains a list, so [0] selects the first user dictionary. The user dictionary contains a roles field, so ['roles'] selects another list. Finally, [1] selects the second element of that list. The correct access expression follows the actual container type at each step.
Knowing the Expected Shape
- 1Check the input before parsing: confirm that the value passed to
json.loads()is a string containing JSON text. - 2Read the outermost symbols: square brackets indicate a list structure, while curly braces indicate a dictionary structure.
- 3Map each nested level: record whether the next access requires a list index or a dictionary key.
- 4Use keys and indices that actually exist in the parsed structure.
- 5If access fails, inspect the structure layer by layer instead of guessing at a longer access expression.
import json
data = '{"users": [{"name": "Ari"}]}'
parsed = json.loads(data)
print(parsed)
print(parsed['users'])
print(parsed['users'][0])
print(parsed['users'][0]['name'])- 1Start with the complete parsed object so you can compare the actual structure with your expectation.
- 2Print one access step at a time.
- 3When a step succeeds, use the revealed value to choose the next key or index.
- 4If a step fails, the failing level identifies where your expectation and the actual structure differ.
- The first print reveals the complete parsed structure.
- The second print reveals the value stored under the users key.
- The third print reveals the dictionary selected at list index 0.
- The final print reveals the value stored under the name key.
{'users': [{'name': 'Ari'}]}
[{'name': 'Ari'}]
{'name': 'Ari'}
AriMistakes During Parsing
Common mistake Forgetting to import json before calling json.loads().
What it looks likedata = '{"name": "Ari"}' parsed = json.loads(data)Why it failsThe name json has not been made available to the program.
Do this insteadImport the json module before using json.loads().
Common mistake Passing a non-string object to json.loads().
What it looks likeparsed = json.loads({'name': 'Ari'})Why it failsjson.loads()is used to parse a JSON string, not an already-created Python object.Do this insteadVerify that the input is a string containing JSON text before calling json.loads().
Common mistake Using a dictionary key where the current value is a list.
What it looks likeparsed['users']['name']Why it failsIf users contains a list, the next step must select a list element before selecting a field.
Do this insteadFollow the structure one level at a time, such as parsed['users'][0]['name'] when that path matches the actual data.
Common mistake Using a list index where the current value is a dictionary.
What it looks likeparsed[0]Why it failsA dictionary is accessed through keys, not list positions.
Do this insteadUse the appropriate dictionary key, such as parsed['users'], when the top-level value is a dictionary.
Common mistake Accessing a field that does not exist.
What it looks likeparsed['username']Why it failsThe requested key may not be present in the parsed dictionary.
Do this insteadCompare the requested key with the documented structure and inspect the parsed value to confirm its available fields.
Practice the Access Path
Given this code, identify the type of container at each step and predict the value printed by the final line:
import json
data = '{"groups": [{"members": ["Ari", "Bea"]}]}'
parsed = json.loads(data)
print(parsed['groups'][0]['members'][1])Hints
- Start by identifying the top-level container.
- After selecting groups, determine whether the next step needs a key or an index.
- The final index selects the second element of the members list.
What do you think happens?
What will the final print statement output?
Reveal answer
Bea
parsed is a dictionary, groups contains a list, index 0 selects the first group dictionary, members contains a list, and index 1 selects its second element.
Key Takeaways
- 1
json.loads()parses a JSON string and returns a new Python data structure; the original string remains unchanged. - 2JSON objects correspond to Python dictionaries, and JSON arrays correspond to Python lists in the parsed structure.
- 3Use dictionary keys for dictionary levels and list indexes for list levels.
- 4Reliable access requires knowing the expected structure, which is why API documentation matters.
- 5When debugging, check the input, identify the parsed structure, and trace each access step separately.
At a glance
json.loads()transforms JSON text into a new Python object.- The JSON shape guides the Python shape: objects become dictionaries and arrays become lists.
- Nested access combines dictionary keys and list indexes according to the structure at each level.
- You need advance knowledge of the expected data structure to navigate parsed JSON effectively.
- Layer-by-layer inspection is a practical way to diagnose parsing and access errors.