Python json — Parse & Serialize JSON
JSON (JavaScript Object Notation) is the most common format for exchanging data between programs, APIs, and config files. Python’s built-in jsonjson module converts between JSON text and Python objects — no installation needed.
import json
data = {"name": "Ada", "age": 36, "skills": ["math", "code"]}
text = json.dumps(data) # Python -> JSON string
print(text) # {"name": "Ada", "age": 36, "skills": ["math", "code"]}
back = json.loads(text) # JSON string -> Python
print(back["skills"][0]) # mathimport json
data = {"name": "Ada", "age": 36, "skills": ["math", "code"]}
text = json.dumps(data) # Python -> JSON string
print(text) # {"name": "Ada", "age": 36, "skills": ["math", "code"]}
back = json.loads(text) # JSON string -> Python
print(back["skills"][0]) # mathThe four functions
The module has two pairs: one works with strings, the other with files.
| Function | Direction | Works with |
|---|---|---|
json.dumps(obj)json.dumps(obj) | Python → JSON | A string (“dump string”). |
json.loads(text)json.loads(text) | JSON → Python | A string (“load string”). |
json.dump(obj, file)json.dump(obj, file) | Python → JSON | A file object. |
json.load(file)json.load(file) | JSON → Python | A file object. |
Remember the s: dumpsdumps/loadsloads end in s for string; dumpdump/loadload are for files.
How types map
Serialization converts Python types to their JSON equivalents (and back):
| Python | JSON |
|---|---|
dictdict | object |
listlist, tupletuple | array |
strstr | string |
intint, floatfloat | number |
TrueTrue / FalseFalse | truetrue / falsefalse |
NoneNone | nullnull |
Note: tuples become JSON arrays, and JSON arrays always load back as lists — so a round-trip turns a tuple into a list.
Serializing: dumpsdumps
import json
data = {"name": "Ada", "active": True, "score": None, "tags": ["a", "b"]}
# Compact (default)
print(json.dumps(data))
# Pretty-printed with indentation
print(json.dumps(data, indent=2))
# Sort keys alphabetically
print(json.dumps(data, sort_keys=True))
# Custom separators for the most compact output
print(json.dumps(data, separators=(",", ":")))import json
data = {"name": "Ada", "active": True, "score": None, "tags": ["a", "b"]}
# Compact (default)
print(json.dumps(data))
# Pretty-printed with indentation
print(json.dumps(data, indent=2))
# Sort keys alphabetically
print(json.dumps(data, sort_keys=True))
# Custom separators for the most compact output
print(json.dumps(data, separators=(",", ":")))Common dumpsdumps / dumpdump options:
| Option | Effect |
|---|---|
indent=nindent=n | Pretty-print with nn spaces per level. |
sort_keys=Truesort_keys=True | Order object keys alphabetically. |
separators=(item, key)separators=(item, key) | Control the item and key-value separators. |
ensure_ascii=Falseensure_ascii=False | Keep non-ASCII characters as-is (e.g. emoji, accents). |
default=funcdefault=func | A fallback function to serialize unknown types. |
import json
data = {"city": "São Paulo", "emoji": "🐍"}
print(json.dumps(data)) # escapes non-ASCII
print(json.dumps(data, ensure_ascii=False)) # keeps São Paulo and 🐍 readableimport json
data = {"city": "São Paulo", "emoji": "🐍"}
print(json.dumps(data)) # escapes non-ASCII
print(json.dumps(data, ensure_ascii=False)) # keeps São Paulo and 🐍 readableParsing: loadsloads
import json
text = '{"name": "Ada", "age": 36, "skills": ["math", "code"], "active": true}'
obj = json.loads(text)
print(type(obj)) # <class 'dict'>
print(obj["name"]) # Ada
print(obj["active"]) # True (JSON true -> Python True)
print(obj["skills"][1]) # codeimport json
text = '{"name": "Ada", "age": 36, "skills": ["math", "code"], "active": true}'
obj = json.loads(text)
print(type(obj)) # <class 'dict'>
print(obj["name"]) # Ada
print(obj["active"]) # True (JSON true -> Python True)
print(obj["skills"][1]) # codeWorking with files
Use dumpdump/loadload to read and write JSON files directly.
import json
config = {"theme": "dark", "version": 2, "plugins": ["a", "b"]}
# Write to a file
with open("config.json", "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
# Read it back
with open("config.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["theme"]) # darkimport json
config = {"theme": "dark", "version": 2, "plugins": ["a", "b"]}
# Write to a file
with open("config.json", "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
# Read it back
with open("config.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["theme"]) # darkHandling errors
Invalid JSON raises json.JSONDecodeErrorjson.JSONDecodeError (a subclass of ValueErrorValueError). Always guard parsing of untrusted input.
import json
bad = '{"name": "Ada", }' # trailing comma is invalid JSON
try:
json.loads(bad)
except json.JSONDecodeError as e:
print("Could not parse:", e)import json
bad = '{"name": "Ada", }' # trailing comma is invalid JSON
try:
json.loads(bad)
except json.JSONDecodeError as e:
print("Could not parse:", e)Serializing custom objects
By default, jsonjson only knows the built-in types. For your own classes, pass a defaultdefault function (or convert to a dict first).
import json
from datetime import datetime
def encode(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Cannot serialize {type(obj).__name__}")
event = {"name": "launch", "when": datetime(2025, 1, 31, 9, 0)}
print(json.dumps(event, default=encode))
# {"name": "launch", "when": "2025-01-31T09:00:00"}import json
from datetime import datetime
def encode(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Cannot serialize {type(obj).__name__}")
event = {"name": "launch", "when": datetime(2025, 1, 31, 9, 0)}
print(json.dumps(event, default=encode))
# {"name": "launch", "when": "2025-01-31T09:00:00"}Practical example — a tiny API response
import json
response = '''
{
"status": "ok",
"users": [
{"id": 1, "name": "Ada"},
{"id": 2, "name": "Linus"}
]
}
'''
data = json.loads(response)
for user in data["users"]:
print(user["id"], "->", user["name"])
# 1 -> Ada
# 2 -> Linusimport json
response = '''
{
"status": "ok",
"users": [
{"id": 1, "name": "Ada"},
{"id": 2, "name": "Linus"}
]
}
'''
data = json.loads(response)
for user in data["users"]:
print(user["id"], "->", user["name"])
# 1 -> Ada
# 2 -> LinusCommon pitfalls
- Single quotes — JSON requires double quotes around keys and strings.
"{'a': 1}""{'a': 1}"fails; use'{"a": 1}''{"a": 1}'. - Trailing commas are invalid in JSON (unlike Python).
TrueTrue/NoneNonevstruetrue/nullnull— Python prints capitalized; JSON uses lowercase. The module handles the conversion for you, but watch for it when hand-writing JSON.- Non-serializable types (sets, datetimes, custom classes) raise
TypeErrorTypeErrorunless you supplydefaultdefault. - Keys become strings — JSON object keys are always strings, so
{1: "a"}{1: "a"}serializes to{"1": "a"}{"1": "a"}.
Practice Exercises
Exercise 1 – Serialize a dictionary
Exercise 2 – Parse JSON and read a value
Exercise 3 – Pretty-print with indentation
Summary
jsonjsonconverts between JSON text and Python objects with four functions:dumpsdumps/loadsloads(strings) anddumpdump/loadload(files).- Python types map cleanly to JSON; tuples and JSON arrays both become lists on the way back.
- Format output with
indentindent,sort_keyssort_keys,separatorsseparators, andensure_asciiensure_ascii. - Guard parsing with
try/except json.JSONDecodeErrortry/except json.JSONDecodeError. - Serialize custom types with a
defaultdefaultfunction.
If this helped you, consider buying me a coffee ☕
Buy me a coffeeWas this page helpful?
Let us know how we did
