Python Course
Working with JSON
JSON — JavaScript Object Notation — is the universal language of data exchange on the web. Every major API, configuration file, and data service you will encounter as a Python developer speaks JSON. Python's built-in json module makes reading, writing, and transforming JSON data straightforward and reliable.
This lesson covers everything from basic parsing to working with files, handling edge cases, and formatting JSON for human readability.
What JSON Looks Like
JSON is built from two structures — objects (key-value pairs in curly braces) and arrays (ordered lists in square brackets). If you know Python dictionaries and lists, JSON will feel immediately familiar.
# JSON looks almost identical to Python dicts and lists
sample_json = '''
{
"name": "Alice",
"age": 30,
"active": true,
"score": 98.5,
"tags": ["python", "data", "ml"],
"address": {
"city": "Austin",
"state": "TX"
},
"nickname": null
}
'''
# true → True in Python
# false → False in Python
# null → None in Python- JSON strings always use double quotes — single quotes are not valid JSON
- JSON
true/false/nullmap directly to PythonTrue/False/None - JSON objects map to Python dicts, JSON arrays map to Python lists
- JSON only supports strings, numbers, booleans, null, objects, and arrays — no dates, sets, or tuples natively
Parsing JSON — json.loads()
json.loads() converts a JSON string into a Python object. The name stands for "load string" — the s is the key distinction from json.load() which reads from a file.
Why it exists: API responses arrive as raw text strings over HTTP. json.loads() turns that raw text into a native Python dictionary or list you can work with immediately.
Real-world use: a weather API returns a JSON string — you parse it and pull out the temperature, city name, and forecast with normal dictionary access.
# json.loads() — parse a JSON string into a Python object
import json
raw = '{"product": "laptop", "price": 999.99, "in_stock": true}'
data = json.loads(raw) # string → Python dict
print(type(data)) #
print(data["product"]) # laptop
print(data["price"]) # 999.99
print(data["in_stock"]) # True (Python bool, not JSON true)
# Nested access works just like a normal dict
response = '{"user": {"id": 42, "name": "Alice"}, "status": "ok"}'
obj = json.loads(response)
print(obj["user"]["name"]) # Alice laptop
999.99
True
Alice
json.loads()takes a string and returns a Python dict, list, str, int, float, bool, or None- The top-level JSON value can be an object, array, string, number, boolean, or null
- Raises
json.JSONDecodeErrorif the string is not valid JSON
Serializing to JSON — json.dumps()
json.dumps() converts a Python object into a JSON string. The name stands for "dump string". This is what you use when you need to send data to an API or store it as text.
Real-world use: building an API response — you construct a Python dictionary with the results, then serialize it to a JSON string to send back to the client.
# json.dumps() — convert a Python object to a JSON string
import json
user = {
"name": "Bob",
"age": 25,
"active": True, # Python True → JSON true
"score": None, # Python None → JSON null
"tags": ["sql", "excel"]
}
raw = json.dumps(user)
print(raw)
print(type(raw)) #
# Pretty-print with indentation — much more readable
pretty = json.dumps(user, indent=4)
print(pretty) <class 'str'>
{
"name": "Bob",
"age": 25,
"active": true,
"score": null,
"tags": [
"sql",
"excel"
]
}
json.dumps()always returns a string — usejson.dump()to write directly to a fileindent=4adds human-readable formatting — use it for config files, debugging, and logssort_keys=Truesorts dictionary keys alphabetically in the output- Python
True→true,False→false,None→nullin the output
Reading JSON from a File — json.load()
json.load() reads directly from a file object — no need to read the file as a string first. This is the standard approach for loading JSON configuration files and datasets.
Real-world use: a Python application reads its settings from a config.json file at startup — database host, port, feature flags, and API keys all stored as structured JSON.
# json.load() — read JSON directly from a file
import json
# First, create a sample JSON file to read
sample = {"app": "dataplexa", "version": "2.1", "debug": False}
with open("config.json", "w") as f:
json.dump(sample, f, indent=2) # write JSON to file
# Now read it back
with open("config.json", "r") as f:
config = json.load(f) # file object → Python dict
print(config)
print("App:", config["app"])
print("Debug mode:", config["debug"])App: dataplexa
Debug mode: False
json.load(f)reads from a file object — the file must be open in text mode ("r")json.dump(obj, f)writes to a file object — the file must be open in write mode ("w")- Always use a
withblock — it closes the file automatically even if an error occurs - Remember:
loads/dumpswork with strings;load/dumpwork with files
Writing JSON to a File — json.dump()
json.dump() serializes a Python object and writes it directly to a file in one step. Combine it with indent to produce clean, readable JSON files.
# json.dump() — write Python data to a JSON file
import json
orders = [
{"id": 1, "item": "notebook", "price": 4.99, "qty": 3},
{"id": 2, "item": "pen", "price": 1.50, "qty": 10},
{"id": 3, "item": "desk", "price": 89.99, "qty": 1}
]
with open("orders.json", "w") as f:
json.dump(orders, f, indent=4) # write list of dicts as JSON array
print("orders.json written successfully.")
# Read it back to verify
with open("orders.json", "r") as f:
loaded = json.load(f)
print("Total orders:", len(loaded))
print("First item:", loaded[0]["item"])Total orders: 3
First item: notebook
Handling Non-Serializable Types
Not every Python object can be converted to JSON automatically. Dates, sets, custom class instances, and Decimal numbers will raise a TypeError by default. You have two options: convert them manually before serializing, or provide a custom encoder.
# Handling types that JSON cannot serialize by default
import json
from datetime import date
# Option 1 — convert manually before dumping
event = {
"title": "Launch",
"date": str(date(2024, 9, 1)), # convert date to string manually
"attendees": list({1, 2, 3}) # convert set to list manually
}
print(json.dumps(event))
# Option 2 — custom default function passed to json.dumps
def json_default(obj):
if isinstance(obj, date):
return obj.isoformat() # "2024-09-01"
raise TypeError(f"Type {type(obj)} not serializable")
event2 = {"title": "Launch", "date": date(2024, 9, 1)}
print(json.dumps(event2, default=json_default)){"title": "Launch", "date": "2024-09-01"}
- Types that are not JSON-serializable by default:
datetime,date,set,tuple(becomes array), custom objects,Decimal - The
defaultparameter accepts a function that handles unrecognized types - Tuples are silently converted to JSON arrays — they round-trip back as lists
Useful json.dumps() Options
A few extra keyword arguments make json.dumps() much more useful in production code.
# Useful json.dumps() keyword arguments
import json
data = {"z_key": 3, "a_key": 1, "m_key": 2}
# sort_keys — alphabetical key order (useful for consistency and diffs)
print(json.dumps(data, sort_keys=True))
# separators — compact output with no extra spaces (smaller payload)
print(json.dumps(data, separators=(",", ":")))
# ensure_ascii=False — preserve non-ASCII characters (e.g. accented letters)
intl = {"city": "São Paulo", "country": "Brasil"}
print(json.dumps(intl, ensure_ascii=False)){"z_key":3,"a_key":1,"m_key":2}
{"city": "São Paulo", "country": "Brasil"}
sort_keys=Truemakes output deterministic — useful for testing and version control diffsseparators=(",", ":")removes all unnecessary spaces — smallest possible JSON stringensure_ascii=Falsekeeps Unicode characters as-is instead of escaping them to\uXXXX
Summary Table
| Function | Direction | Works With |
|---|---|---|
json.loads(s) |
JSON string → Python object | Strings (API responses, raw text) |
json.dumps(obj) |
Python object → JSON string | Strings (send to API, store as text) |
json.load(f) |
JSON file → Python object | File objects (config files, datasets) |
json.dump(obj, f) |
Python object → JSON file | File objects (saving data to disk) |
Practice Questions
Practice 1. Which function converts a JSON string into a Python object?
Practice 2. What Python value does JSON null map to?
Practice 3. Which json.dumps() parameter adds indentation for human-readable output?
Practice 4. What is the key difference between json.loads() and json.load()?
Practice 5. What exception does json.loads() raise when given invalid JSON?
Quiz
Quiz 1. What does json.dumps({"active": True, "score": None}) produce?
Quiz 2. Which of the following Python types cannot be serialized by json.dumps() without extra handling?
Quiz 3. What does json.dumps(data, sort_keys=True) do?
Quiz 4. If a JSON file contains an array at the top level, what Python type does json.load() return?
Quiz 5. What does the default parameter in json.dumps() do?
Next up — Date & Time: working with dates, times, and timedeltas using Python's datetime module.