What is JSON?
JSON (JavaScript Object Notation) is the most common data format for exchanging information between systems. APIs return JSON, config files use JSON, and databases store JSON. If you work with any external data, you'll work with JSON.
{
"name": "Alice",
"age": 25,
"is_admin": false,
"skills": ["Python", "Linux", "Security"],
"address": {
"city": "London",
"country": "UK"
}
}
JSON objects become Python dicts, JSON arrays become lists, true/false
become True/False, and null becomes None.
Parsing JSON Strings
import json
# JSON string → Python dict
json_string = '{"name": "Alice", "age": 25, "active": true}'
data = json.loads(json_string)
print(data["name"]) # Alice
print(data["age"]) # 25
print(type(data)) # <class 'dict'>
# Python dict → JSON string
user = {"name": "Bob", "age": 30, "active": True}
json_output = json.dumps(user)
print(json_output) # {"name": "Bob", "age": 30, "active": true}
# Pretty-print JSON
print(json.dumps(user, indent=2))
# {
# "name": "Bob",
# "age": 30,
# "active": true
# }
Reading JSON Files
import json
# Read a JSON file
with open("config.json", "r") as file:
config = json.load(file) # Note: load (not loads)
print(config["database"]["host"])
print(config["debug"])
Writing JSON Files
import json
data = {
"users": [
{"name": "Alice", "role": "admin"},
{"name": "Bob", "role": "user"}
],
"version": "1.0",
"last_updated": "2026-03-04"
}
# Write to file (pretty-printed)
with open("data.json", "w") as file:
json.dump(data, file, indent=2) # Note: dump (not dumps)
loads/dumps work with strings (the "s" stands for string).
load/dump work with files.
Handling JSON Errors
import json
# Invalid JSON will raise JSONDecodeError
bad_json = '{"name": "Alice", age: 25}' # Missing quotes around key
try:
data = json.loads(bad_json)
except json.JSONDecodeError as e:
print(f"Invalid JSON: {e}")
# Invalid JSON: Expecting property name enclosed in double quotes
Working with Nested JSON
import json
response = '''
{
"status": "success",
"data": {
"users": [
{"id": 1, "name": "Alice", "email": "alice@example.com"},
{"id": 2, "name": "Bob", "email": "bob@example.com"}
],
"total": 2
}
}
'''
data = json.loads(response)
# Access nested values
print(data["status"]) # success
print(data["data"]["total"]) # 2
# Loop through nested arrays
for user in data["data"]["users"]:
print(f"{user['name']}: {user['email']}")
# Safe access with .get() (avoids KeyError)
phone = data["data"]["users"][0].get("phone", "Not provided")
print(phone) # Not provided
Practical Examples
Config File Manager
import json
from pathlib import Path
class Config:
def __init__(self, filename):
self.filename = filename
self.data = {}
self._load()
def _load(self):
path = Path(self.filename)
if path.exists():
with open(self.filename, "r") as f:
self.data = json.load(f)
def save(self):
with open(self.filename, "w") as f:
json.dump(self.data, f, indent=2)
def get(self, key, default=None):
return self.data.get(key, default)
def set(self, key, value):
self.data[key] = value
self.save()
# Usage
config = Config("app_settings.json")
config.set("theme", "dark")
config.set("language", "en")
config.set("notifications", True)
print(config.get("theme")) # dark
Log Analyzer
import json
# Parse JSON log entries
log_entries = [
'{"timestamp": "2026-03-04T10:30:00", "level": "INFO", "message": "Server started"}',
'{"timestamp": "2026-03-04T10:30:05", "level": "ERROR", "message": "Database timeout"}',
'{"timestamp": "2026-03-04T10:30:10", "level": "INFO", "message": "Retry successful"}',
'{"timestamp": "2026-03-04T10:31:00", "level": "ERROR", "message": "Disk space low"}'
]
errors = []
for entry_str in log_entries:
entry = json.loads(entry_str)
if entry["level"] == "ERROR":
errors.append(entry)
print(f"Found {len(errors)} errors:")
for error in errors:
print(f" [{error['timestamp']}] {error['message']}")
Data Transformation
import json
# Transform JSON data between formats
api_response = '''
[
{"first_name": "Alice", "last_name": "Smith", "age": 25},
{"first_name": "Bob", "last_name": "Jones", "age": 30}
]
'''
users = json.loads(api_response)
# Transform to a different format
transformed = {
user["first_name"].lower(): {
"full_name": f"{user['first_name']} {user['last_name']}",
"age": user["age"]
}
for user in users
}
print(json.dumps(transformed, indent=2))
# {
# "alice": {"full_name": "Alice Smith", "age": 25},
# "bob": {"full_name": "Bob Jones", "age": 30}
# }
JSON Serialization Tips
import json
from datetime import datetime
# Problem: datetime is not JSON serializable
data = {"timestamp": datetime.now()}
# json.dumps(data) # TypeError!
# Solution: custom serializer
def json_serial(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Type {type(obj)} not serializable")
json_output = json.dumps(data, default=json_serial)
print(json_output) # {"timestamp": "2026-03-04T10:30:00.000000"}
# Other useful dumps options
json.dumps(data, default=json_serial,
indent=2, # Pretty print
sort_keys=True, # Alphabetical keys
ensure_ascii=False) # Allow unicode characters
Summary
json.loads(string)parses a JSON string into Python objectsjson.dumps(obj)converts Python objects to a JSON stringjson.load(file)reads JSON from a filejson.dump(obj, file)writes JSON to a file- Use
indent=2for human-readable output - Use
.get(key, default)for safe access to nested data - Handle
json.JSONDecodeErrorfor invalid JSON input
You can now exchange data with APIs, save configurations, and process structured data. Next up: regular expressions — powerful pattern matching for text processing.