Skip to content

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.

quickstart.py
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])        # math
quickstart.py
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])        # math

The four functions

The module has two pairs: one works with strings, the other with files.

FunctionDirectionWorks with
json.dumps(obj)json.dumps(obj)Python → JSONA string (“dump string”).
json.loads(text)json.loads(text)JSON → PythonA string (“load string”).
json.dump(obj, file)json.dump(obj, file)Python → JSONA file object.
json.load(file)json.load(file)JSON → PythonA 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):

PythonJSON
dictdictobject
listlist, tupletuplearray
strstrstring
intint, floatfloatnumber
TrueTrue / FalseFalsetruetrue / falsefalse
NoneNonenullnull

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

dumps.py
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=(",", ":")))
dumps.py
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:

OptionEffect
indent=nindent=nPretty-print with nn spaces per level.
sort_keys=Truesort_keys=TrueOrder object keys alphabetically.
separators=(item, key)separators=(item, key)Control the item and key-value separators.
ensure_ascii=Falseensure_ascii=FalseKeep non-ASCII characters as-is (e.g. emoji, accents).
default=funcdefault=funcA fallback function to serialize unknown types.
unicode.py
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 🐍 readable
unicode.py
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 🐍 readable

Parsing: loadsloads

loads.py
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])   # code
loads.py
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])   # code

Working with files

Use dumpdump/loadload to read and write JSON files directly.

files.py
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"])    # dark
files.py
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"])    # dark

Handling errors

Invalid JSON raises json.JSONDecodeErrorjson.JSONDecodeError (a subclass of ValueErrorValueError). Always guard parsing of untrusted input.

errors.py
import json
 
bad = '{"name": "Ada", }'   # trailing comma is invalid JSON
 
try:
    json.loads(bad)
except json.JSONDecodeError as e:
    print("Could not parse:", e)
errors.py
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).

custom.py
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"}
custom.py
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

api_like.py
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 -> Linus
api_like.py
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 -> Linus

Common 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/NoneNone vs truetrue/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 TypeErrorTypeError unless you supply defaultdefault.
  • 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

  • jsonjson converts between JSON text and Python objects with four functions: dumpsdumps/loadsloads (strings) and dumpdump/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, and ensure_asciiensure_ascii.
  • Guard parsing with try/except json.JSONDecodeErrortry/except json.JSONDecodeError.
  • Serialize custom types with a defaultdefault function.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did