Working with JSON
Objectives
By the end of this chapter, you should be able to:
- Explain what JSON is and where it shows up
- Read and write JSON files with the
jsonmodule - Convert between JSON strings and Python objects
💡 Why this matters: JSON is the format most APIs speak, and a common choice for config files and saved application data. You’ve already seen it come back from an API response, now you’ll read and write it yourself.
What Is JSON?
JSON (JavaScript Object Notation) is a lightweight, text-based format for structured data. It maps closely onto Python’s own dictionaries and lists:
{
"name": "Erin",
"age": 29,
"skills": ["Python", "SQL"],
"active": true
}
Objects ({}) become dictionaries, arrays ([]) become lists, and strings, numbers, booleans, and null map directly onto Python’s str, int/float, bool, and None.
Reading a JSON File
The json module handles the conversion for you. json.load() reads a file object and returns a Python object. Say data.json contains:
{
"name": "Erin",
"age": 29,
"skills": ["Python", "SQL"],
"active": true
}
import json
with open("data.json") as f:
data = json.load(f)
print(data) # {'name': 'Erin', 'age': 29, 'skills': ['Python', 'SQL'], 'active': True}
print(type(data)) # <class 'dict'>, just like any other Python value
print(data["name"]) # Erin, access it the same way you would any dict
Writing a JSON File
json.dump() writes a Python object out as JSON:
import json
person = {
"name": "Jordan",
"age": 31,
"skills": ["Python", "Docker"],
}
with open("person.json", "w") as f:
json.dump(person, f)
Pass indent=2 to get readable, multi-line output instead of one long line, handy for files a human might open:
with open("person.json", "w") as f:
json.dump(person, f, indent=2)
Converting Without a File: loads and dumps
Sometimes you have JSON as a plain string already (from an API response, for instance) rather than in a file. json.loads() (load-string) parses a JSON string directly into a Python object, and json.dumps() (dump-string) does the reverse:
import json
json_string = '{"name": "Maya", "age": 27}'
data = json.loads(json_string)
print(data["name"]) # Maya
python_dict = {"name": "Priya", "age": 33}
print(json.dumps(python_dict)) # {"name": "Priya", "age": 33}
This is exactly what’s happening under the hood when you call .json() on a requests response: it’s parsing the response body’s JSON string into a Python dictionary for you.
A Quick Comparison with CSV
JSON and CSV solve a similar problem, persisting structured data, but fit different shapes of data. CSV is a great match for uniform, tabular rows (like a spreadsheet); JSON handles nested and irregular structures far more naturally, since a JSON value can itself contain lists and dictionaries several layers deep:
import json
person = {
"name": "Sam",
"address": {"city": "Austin", "zip": "78701"},
"hobbies": ["chess", "hiking"],
}
print(json.dumps(person, indent=2))
{
"name": "Sam",
"address": {
"city": "Austin",
"zip": "78701"
},
"hobbies": [
"chess",
"hiking"
]
}
A CSV row can’t naturally hold a nested address dictionary or a hobbies list. It’s flat by design; JSON isn’t.
Try It
- Write a Python dictionary describing something in your own life, and save it to a
.jsonfile withjson.dump(). - Read that file back with
json.load()and confirm you get an equal dictionary. - Take a JSON string (write one by hand, or copy one from an API response) and parse it with
json.loads().
Recap
- JSON maps closely onto Python’s own data structures: objects become dicts, arrays become lists.
json.load()/json.dump()read and write JSON files;json.loads()/json.dumps()convert to and from JSON strings directly, without a file.indent=2(or any number) makesjson.dump()output human-readable instead of a single line.
Next lesson: put file I/O into practice with a set of exercises.