- What is JSON — the most common data format for APIs
- loads() — parse JSON strings to Python objects
- dumps() — convert Python objects to JSON strings
- load() — read JSON from files
- dump() — write JSON to files
- Advanced options — pretty printing, custom serialization
What is JSON?
JSON (JavaScript Object Notation) is a lightweight data format that is easy for humans to read and write, and easy for machines to parse and generate. It's the most common format for sending data between servers and web applications.
Think of JSON like a universal translator for data. Python, JavaScript, Java, C#, and almost every programming language can understand JSON. It's the common language that allows different systems to talk to each other.
JSON looks a lot like Python dictionaries and lists, but with a few differences. It's perfect for storing and exchanging data.
💡 Key concept: JSON is the most common data format for APIs. Python's JSON module helps you convert between JSON and Python objects.
Parsing JSON - loads()
Convert JSON Strings to Python Objects
loads() (load string) converts a JSON string into a Python object.
# Parsing JSON - loads()
import json
print("=" * 50)
print("PARSING JSON - LOADS()")
print("=" * 50)
# ============================================================
# PARSE JSON STRING
# ============================================================
print("\n1. PARSE JSON STRING")
# JSON string
json_str = '{"name": "Alice", "age": 30, "city": "NYC"}'
print(f" JSON string: {json_str}")
# Parse to Python dict
data = json.loads(json_str)
print(f" Python dict: {data}")
print(f" Type: {type(data)}")
print(f" Name: {data['name']}")
print(f" Age: {data['age']}")
print(f" City: {data['city']}")
# ============================================================
# PARSE JSON ARRAY
# ============================================================
print("\n2. PARSE JSON ARRAY")
json_array = '[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]'
print(f" JSON array: {json_array}")
data = json.loads(json_array)
print(f" Python list: {data}")
print(f" Type: {type(data)}")
print(f" First person: {data[0]}")
print(f" Second person: {data[1]}")
# ============================================================
# JSON TO PYTHON MAPPING
# ============================================================
print("\n3. JSON TO PYTHON MAPPING")
print("""
┌──────────────┬──────────────────────┐
│ JSON Type │ Python Type │
├──────────────┼──────────────────────┤
│ object │ dict │
│ array │ list │
│ string │ str │
│ number │ int or float │
│ true │ True │
│ false │ False │
│ null │ None │
└──────────────┴──────────────────────┘
""")
# ============================================================
# COMPLEX JSON
# ============================================================
print("\n4. COMPLEX JSON")
complex_json = '''
{
"name": "Alice",
"age": 30,
"is_active": true,
"score": null,
"skills": ["Python", "JavaScript", "SQL"],
"address": {
"street": "123 Main St",
"city": "NYC",
"zip": "10001"
},
"projects": [
{"name": "Project A", "status": "active"},
{"name": "Project B", "status": "completed"}
]
}
'''
data = json.loads(complex_json)
print(f" Name: {data['name']}")
print(f" Is active: {data['is_active']}")
print(f" Skills: {data['skills']}")
print(f" City: {data['address']['city']}")
print(f" First project: {data['projects'][0]['name']}")
loads() key points:
- loads() — parse JSON string to Python
- JSON object — becomes Python dict
- JSON array — becomes Python list
- Types map — JSON types map to Python types
Quick Check: What function converts a JSON string to a Python object? (Answer: json.loads())
Creating JSON - dumps()
Convert Python Objects to JSON Strings
dumps() (dump string) converts a Python object into a JSON string.
# Creating JSON - dumps()
import json
print("=" * 50)
print("CREATING JSON - DUMPS()")
print("=" * 50)
# ============================================================
# BASIC CONVERSION
# ============================================================
print("\n1. BASIC CONVERSION")
# Python dict
data = {
"name": "Alice",
"age": 30,
"city": "NYC",
"is_active": True,
"score": None
}
print(f" Python dict: {data}")
# Convert to JSON
json_str = json.dumps(data)
print(f" JSON string: {json_str}")
print(f" Type: {type(json_str)}")
# ============================================================
# LIST TO JSON
# ============================================================
print("\n2. LIST TO JSON")
people = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
json_str = json.dumps(people)
print(f" Python list: {people}")
print(f" JSON string: {json_str}")
# ============================================================
# PRETTY PRINTING (indent)
# ============================================================
print("\n3. PRETTY PRINTING (indent)")
data = {
"name": "Alice",
"age": 30,
"skills": ["Python", "JavaScript", "SQL"],
"address": {
"street": "123 Main St",
"city": "NYC"
}
}
# Without pretty printing
json_str = json.dumps(data)
print(f" Without indent: {json_str}")
# With pretty printing
json_pretty = json.dumps(data, indent=2)
print(f" With indent=2:")
print(json_pretty)
# With different indent size
json_pretty4 = json.dumps(data, indent=4)
print(f"\n With indent=4:")
print(json_pretty4)
# ============================================================
# SORTING KEYS
# ============================================================
print("\n4. SORTING KEYS")
data = {"z": 1, "a": 2, "m": 3, "b": 4}
# Without sorting
print(f" Without sort: {json.dumps(data)}")
# With sorting
print(f" With sort: {json.dumps(data, sort_keys=True)}")
# ============================================================
# SEPARATORS - Compact JSON
# ============================================================
print("\n5. SEPARATORS")
data = {"name": "Alice", "age": 30}
# Default separators
print(f" Default: {json.dumps(data)}")
# Compact separators (no spaces)
print(f" Compact: {json.dumps(data, separators=(',', ':'))}")
dumps() key points:
- dumps() — convert Python to JSON string
- indent — pretty print with indentation
- sort_keys — sort dictionary keys
- separators — control spacing
Quick Check: What parameter makes JSON output readable? (Answer: indent)
Reading Files - load()
Read JSON from Files
load() reads JSON from a file and converts it to Python objects.
# Reading Files - load()
import json
print("=" * 50)
print("READING FILES - LOAD()")
print("=" * 50)
# ============================================================
# CREATE SAMPLE JSON FILE
# ============================================================
print("\n1. CREATE SAMPLE JSON FILE")
sample_data = {
"users": [
{"id": 1, "name": "Alice", "email": "alice@example.com"},
{"id": 2, "name": "Bob", "email": "bob@example.com"}
],
"total": 2
}
# Write sample data to file
with open("users.json", "w") as f:
json.dump(sample_data, f, indent=2)
print(" Created users.json")
# ============================================================
# READ JSON FILE
# ============================================================
print("\n2. READ JSON FILE")
# Read the JSON file
with open("users.json", "r") as f:
data = json.load(f)
print(f" Data type: {type(data)}")
print(f" Total users: {data['total']}")
print(" Users:")
for user in data['users']:
print(f" {user['id']}: {user['name']} ({user['email']})")
# ============================================================
# READ FROM API RESPONSE
# ============================================================
print("\n3. READ FROM API RESPONSE")
# Simulating an API response
api_response = '''
{
"status": "success",
"data": {
"user": {
"id": 123,
"name": "Charlie",
"email": "charlie@example.com"
}
}
}
'''
# Parse the response
response = json.loads(api_response)
if response['status'] == 'success':
user = response['data']['user']
print(f" User: {user['name']} ({user['email']})")
else:
print(" API call failed")
load() key points:
- load() — reads JSON from file
- Works with file objects — use with open()
- Returns Python objects — dict, list, etc.
Quick Check: What function reads JSON from a file? (Answer: json.load())
Writing Files - dump()
Write JSON to Files
dump() writes Python objects to a file in JSON format.
# Writing Files - dump()
import json
print("=" * 50)
print("WRITING FILES - DUMP()")
print("=" * 50)
# ============================================================
# BASIC WRITE
# ============================================================
print("\n1. BASIC WRITE")
data = {
"name": "Alice",
"age": 30,
"city": "NYC",
"is_active": True
}
# Write to file
with open("user.json", "w") as f:
json.dump(data, f)
print(" Written to user.json")
# Check the content
with open("user.json", "r") as f:
content = f.read()
print(f" File content: {content}")
# ============================================================
# PRETTY PRINT WRITE
# ============================================================
print("\n2. PRETTY PRINT WRITE")
data = {
"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
],
"total": 2
}
# Write with indentation
with open("pretty_users.json", "w") as f:
json.dump(data, f, indent=2)
print(" Written to pretty_users.json with indent")
# Show content
with open("pretty_users.json", "r") as f:
print(f.read())
# ============================================================
# WRITE WITH SORTING
# ============================================================
print("\n3. WRITE WITH SORTING")
data = {"z": 1, "a": 2, "m": 3}
with open("sorted.json", "w") as f:
json.dump(data, f, sort_keys=True, indent=2)
print(" Written to sorted.json with sorted keys")
# ============================================================
# UPDATE EXISTING FILE
# ============================================================
print("\n4. UPDATE EXISTING FILE")
# Read existing data
with open("users.json", "r") as f:
data = json.load(f)
print(f" Original users: {len(data['users'])}")
# Add new user
data['users'].append({"id": 3, "name": "Charlie", "email": "charlie@example.com"})
data['total'] = len(data['users'])
# Write back
with open("users.json", "w") as f:
json.dump(data, f, indent=2)
print(f" Updated users: {len(data['users'])}")
dump() key points:
- dump() — writes JSON to file
- indent — pretty print
- sort_keys — sort dictionary keys
- Read then write — to update existing files
Quick Check: What function writes JSON to a file? (Answer: json.dump())
Advanced Options
Custom Serialization and More
The JSON module has advanced options for handling special cases.
# Advanced JSON Options
import json
from datetime import datetime
print("=" * 50)
print("ADVANCED OPTIONS")
print("=" * 50)
# ============================================================
# CUSTOM ENCODER FOR DATETIME
# ============================================================
print("\n1. CUSTOM ENCODER FOR DATETIME")
class DateTimeEncoder(json.JSONEncoder):
"""Custom encoder for datetime objects"""
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
data = {
"name": "Alice",
"created": datetime.now()
}
# Without custom encoder (fails)
try:
json.dumps(data)
except TypeError as e:
print(f" Without custom encoder: {e}")
# With custom encoder
json_str = json.dumps(data, cls=DateTimeEncoder)
print(f" With custom encoder: {json_str}")
# ============================================================
# CUSTOM DECODER
# ============================================================
print("\n2. CUSTOM DECODER")
def custom_decoder(obj):
"""Custom decoder for datetime strings"""
if '__datetime__' in obj:
return datetime.fromisoformat(obj['__datetime__'])
return obj
# Encode with datetime marker
data = {
"name": "Alice",
"created": {
"__datetime__": datetime.now().isoformat()
}
}
json_str = json.dumps(data)
print(f" JSON: {json_str}")
# Decode with custom decoder
decoded = json.loads(json_str, object_hook=custom_decoder)
print(f" Decoded: {decoded}")
# ============================================================
# HANDLING NON-SERIALIZABLE TYPES
# ============================================================
print("\n3. HANDLING NON-SERIALIZABLE TYPES")
# Using default parameter to handle custom objects
def default_serializer(obj):
if isinstance(obj, datetime):
return obj.isoformat()
if hasattr(obj, '__dict__'):
return obj.__dict__
raise TypeError(f"Type {type(obj)} not serializable")
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 30)
data = {"person": person, "timestamp": datetime.now()}
json_str = json.dumps(data, default=default_serializer)
print(f" Custom serialization: {json_str}")
# ============================================================
# SKIP NON-SERIALIZABLE VALUES
# ============================================================
print("\n4. SKIP NON-SERIALIZABLE VALUES")
class User:
def __init__(self, name):
self.name = name
data = {
"name": "Alice",
"user": User("Bob"), # Non-serializable
"age": 30
}
# Without skipping (fails)
try:
json.dumps(data)
except TypeError as e:
print(f" Without skip: {e}")
# Not directly supported, use default to skip
# ============================================================
# COMPACT JSON FOR NETWORK TRANSFER
# ============================================================
print("\n5. COMPACT JSON FOR NETWORK TRANSFER")
data = {"name": "Alice", "age": 30, "city": "NYC"}
# Regular
regular = json.dumps(data)
print(f" Regular: {regular} (length: {len(regular)})")
# Compact (no spaces)
compact = json.dumps(data, separators=(',', ':'))
print(f" Compact: {compact} (length: {len(compact)})")
# Network transfer uses compact JSON to save bandwidth
Advanced options key points:
- Custom encoder — handle datetime and custom objects
- Custom decoder — convert JSON back to custom objects
- default parameter — handle non-serializable types
- Compact JSON — save bandwidth
Quick Check: How do you handle datetime objects in JSON? (Answer: Create a custom encoder that converts datetime to ISO format)
Real-World Example
Building a User API Client
# Real-World Example: User API Client
import json
import requests
from datetime import datetime
print("=" * 60)
print("USER API CLIENT")
print("=" * 60)
# ============================================================
# SAMPLE API RESPONSE (Simulated)
# ============================================================
api_response = '''
{
"status": "success",
"code": 200,
"data": {
"users": [
{
"id": 1,
"name": "Alice Johnson",
"email": "alice@example.com",
"age": 30,
"is_active": true,
"joined": "2023-01-15T10:30:00",
"preferences": {
"theme": "dark",
"notifications": true
},
"skills": ["Python", "JavaScript", "SQL"]
},
{
"id": 2,
"name": "Bob Smith",
"email": "bob@example.com",
"age": 25,
"is_active": false,
"joined": "2023-03-20T14:45:00",
"preferences": {
"theme": "light",
"notifications": false
},
"skills": ["Java", "C++"]
}
],
"total": 2,
"page": 1
}
}
'''
# ============================================================
# PARSE API RESPONSE
# ============================================================
print("\n1. PARSING API RESPONSE")
response = json.loads(api_response)
print(f" Status: {response['status']}")
print(f" Code: {response['code']}")
print(f" Total users: {response['data']['total']}")
users = response['data']['users']
for user in users:
print(f"\n User {user['id']}:")
print(f" Name: {user['name']}")
print(f" Email: {user['email']}")
print(f" Age: {user['age']}")
print(f" Active: {user['is_active']}")
print(f" Joined: {user['joined']}")
print(f" Theme: {user['preferences']['theme']}")
print(f" Skills: {', '.join(user['skills'])}")
# ============================================================
# PROCESS AND TRANSFORM DATA
# ============================================================
print("\n2. PROCESS AND TRANSFORM DATA")
def transform_user(user):
"""Transform user data for display"""
return {
"display_name": user['name'].upper(),
"age_group": "Adult" if user['age'] >= 18 else "Minor",
"active_status": "Active" if user['is_active'] else "Inactive",
"skill_count": len(user['skills']),
"joined_date": datetime.fromisoformat(user['joined']).strftime("%B %d, %Y")
}
transformed_users = [transform_user(user) for user in users]
print(" Transformed users:")
for user in transformed_users:
print(f" {user}")
# ============================================================
# FILTER AND EXPORT
# ============================================================
print("\n3. FILTER AND EXPORT")
# Filter active users
active_users = [user for user in users if user['is_active']]
print(f" Active users: {len(active_users)}")
# Create summary
summary = {
"total": len(users),
"active": len(active_users),
"inactive": len(users) - len(active_users),
"average_age": sum(u['age'] for u in users) / len(users),
"exported_at": datetime.now().isoformat()
}
print(f" Summary: {json.dumps(summary, indent=2)}")
# ============================================================
# EXPORT TO JSON FILE
# ============================================================
print("\n4. EXPORT TO JSON FILE")
# Save transformed data
output = {
"summary": summary,
"users": transformed_users
}
with open("exported_users.json", "w") as f:
json.dump(output, f, indent=2)
print(" Exported to exported_users.json")
# ============================================================
# READ BACK
# ============================================================
print("\n5. READ BACK FROM FILE")
with open("exported_users.json", "r") as f:
data = json.load(f)
print(f" Read back: {len(data['users'])} users")
print(f" Summary: {data['summary']}")
print("\n" + "=" * 60)
print("KEY TAKEAWAYS:")
print("=" * 60)
print("""
- JSON is the universal data format
- loads/dumps for string conversion
- load/dump for file operations
- Custom serialization for special types
- Perfect for API data processing
""")
Real-world example key points:
- Parse API responses — load JSON from APIs
- Transform data — process JSON data
- Filter and summarize — extract useful information
- Export — save processed data as JSON
Quick Check: What's the most common use of JSON in Python? (Answer: Working with API responses)
Best Practices
Using JSON Effectively
# Best Practices for JSON
import json
from datetime import datetime
print("=" * 60)
print("BEST PRACTICES FOR JSON")
print("=" * 60)
# ============================================================
# 1. USE INDENT FOR READABILITY
# ============================================================
print("\n1. USE INDENT FOR READABILITY")
data = {"name": "Alice", "age": 30, "city": "NYC"}
# Good - readable
pretty = json.dumps(data, indent=2)
print(f" With indent: {pretty}")
# Bad - hard to read
ugly = json.dumps(data)
print(f" Without indent: {ugly}")
# ============================================================
# 2. VALIDATE JSON BEFORE PARSING
# ============================================================
print("\n2. VALIDATE JSON BEFORE PARSING")
def safe_json_loads(json_str):
try:
return json.loads(json_str)
except json.JSONDecodeError as e:
print(f" Invalid JSON: {e}")
return None
# Valid JSON
valid = '{"name": "Alice"}'
result = safe_json_loads(valid)
print(f" Valid: {result}")
# Invalid JSON
invalid = '{"name": "Alice",}' # Trailing comma
result = safe_json_loads(invalid)
print(f" Invalid: {result}")
# ============================================================
# 3. USE WITH STATEMENT FOR FILES
# ============================================================
print("\n3. USE WITH STATEMENT FOR FILES")
# Good - automatically closes file
with open("data.json", "w") as f:
json.dump({"key": "value"}, f)
with open("data.json", "r") as f:
data = json.load(f)
print(f" Read data: {data}")
# Bad - manual close (error-prone)
# f = open("data.json", "w")
# json.dump({"key": "value"}, f)
# f.close() # Easy to forget!
# ============================================================
# 4. HANDLE ENCODING
# ============================================================
print("\n4. HANDLE ENCODING")
# Use UTF-8 encoding for compatibility
with open("data.json", "w", encoding="utf-8") as f:
json.dump({"name": "Alice"}, f)
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
print(f" With encoding: {data}")
# ============================================================
# 5. USE CUSTOM ENCODERS FOR NON-STANDARD TYPES
# ============================================================
print("\n5. USE CUSTOM ENCODERS")
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
data = {"created": datetime.now()}
json_str = json.dumps(data, cls=DateTimeEncoder)
print(f" Custom encoder: {json_str}")
# ============================================================
# 6. SUMMARY
# ============================================================
print("\n" + "=" * 60)
print("BEST PRACTICES SUMMARY")
print("=" * 60)
print("""
- Use indent for readable JSON
- Validate JSON before parsing
- Use with statements for files
- Specify UTF-8 encoding
- Use custom encoders for special types
- Handle JSONDecodeError exceptions
- Use compact JSON for network transfer
""")
Best practices summary:
- Use indent — for readability
- Validate JSON — handle parsing errors
- Use with — for file operations
- Encoding — use UTF-8
- Custom encoders — for special types
Quick Check: How should you handle JSON parsing errors? (Answer: Use try/except with json.JSONDecodeError)
Try It Yourself
Experiment with JSON in the editor below.
JSON - PRACTICE
==================================================
1. PARSE JSON STRING
Parsed: {'name': 'Alice', 'age': 30, 'city': 'NYC'}
Name: Alice
2. CONVERT TO JSON
JSON:
{
"name": "Bob",
"age": 25,
"skills": [
"Python",
"Java"
],
"is_active": true
}
3. READ FROM FILE
Read: {'users': [{'id': 1, 'name': 'Alice'}]}
4. PRETTY PRINT
Without: {"name": "Alice", "age": 30, "address": {"city": "NYC", "zip": "10001"}}
With indent:
{
"name": "Alice",
"age": 30,
"address": {
"city": "NYC",
"zip": "10001"
}
}
You've Got It!
You now understand the JSON module in Python. You know how to parse JSON, create JSON, read and write files, and handle advanced cases.
Quick Quiz
Test what you've learned:
Frequently Asked Questions
What is JSON in Python?
What's the difference between load() and loads()?
How do I handle datetime in JSON?
Can JSON store Python objects?
How do I handle large JSON files?
What's the most common use of JSON in Python?
Where to Go From Here
Now that you understand the JSON module, check out these related topics:
OS Module
Learn about file and directory operations.
Learn More →Sys Module
Learn about system-specific parameters and functions.
Learn More →Datetime Module
Learn about handling dates and times in JSON.
Learn More →