JSON
Introduction
JSON (JavaScript Object Notation) is a lightweight data format used to exchange information between applications. Despite its name, JSON is language-independent, meaning almost every programming language can read and write JSON.
JSON is commonly used in APIs, configuration files, and data storage. In Python, JSON can be easily converted to and from dictionaries, lists, and other Python objects using the built-in json module.
Concepts
- Data is written as key-value pairs.
- Keys must be strings (wrapped in quotes).
- Values can be
strings,numbers,booleans,arrays,objects, ornull. - Cannot contain functions or other non-serializable Python objects.
Converting Between JSON and Python
- Convert Python object → JSON string:
json.dumps(obj) - Convert JSON string → Python object:
json.loads(json_string) - Read JSON from file:
json.load(file) - Write JSON to file:
json.dump(obj, file)
Python ↔ JSON Type Mapping
dict↔ JSON objectlist,tuple↔ JSON arraystr↔ JSON stringint,float↔ JSON numberTrue/False↔ JSONtrue/falseNone↔ JSONnull
Examples
import json
# Python dictionary
student = {
"name": "Alice",
"age": 25,
"is_student": True,
"courses": ["Math", "Science"],
"address": None
}
# Convert dictionary to JSON string
json_str = json.dumps(student)
print(json_str)
# {"name": "Alice", "age": 25, "is_student": true, "courses": ["Math", "Science"], "address": null}
# Convert JSON string back to dictionary
parsed_dict = json.loads(json_str)
print(parsed_dict["name"]) # Alice
# Pretty-printed JSON
pretty_json = json.dumps(student, indent=2)
print(pretty_json)
# Working with files
with open("student.json", "w") as f:
json.dump(student, f, indent=2)
with open("student.json", "r") as f:
loaded_student = json.load(f)
print(loaded_student)
Challenges
1. Create JSON for a book and parse
- Create a JSON string representing a book with
title,author, andyear. - Parse it into a dictionary and print the title.
💡 Show Answer
import json
book_json = '{"title": "1984", "author": "George Orwell", "year": 1949}'
book = json.loads(book_json)
print(book["title"]) # 1984
# Alternative: create dictionary first, then convert to JSON
book_dict = {"title": "1984", "author": "George Orwell", "year": 1949}
book_json = json.dumps(book_dict)
print(book_json)
2. List to JSON and back
- Convert a list
[10, 20, 30]into JSON and back.
💡 Show Answer
import json
arr = [10, 20, 30]
json_str = json.dumps(arr)
print(f"JSON: {json_str}") # [10, 20, 30]
back_to_list = json.loads(json_str)
print(f"Back to list: {back_to_list}")
print(f"Second element: {back_to_list[1]}") # 20
# Type verification
print(f"Original type: {type(arr)}")
print(f"Parsed type: {type(back_to_list)}")
3. Car dictionary to JSON
- Create a Python dictionary representing a
car, convert it to JSON, and print the string.
💡 Show Answer
import json
car = {
"make": "Toyota",
"model": "Corolla",
"year": 2022,
"is_electric": False,
"features": ["GPS", "Bluetooth", "Backup Camera"]
}
car_json = json.dumps(car)
print(car_json)
# Pretty-printed version
print(json.dumps(car, indent=2))
# With sorted keys
print(json.dumps(car, indent=2, sort_keys=True))
4. Parse JSON string
- Parse the following JSON string and print the student's course:
{"name":"Bob","age":21,"course":"Math"}
💡 Show Answer
import json
student_json = '{"name":"Bob","age":21,"course":"Math"}'
student = json.loads(student_json)
print(student["course"]) # Math
# Safe access with get()
course = student.get("course", "Unknown")
print(f"Course: {course}")
# Print all student info
for key, value in student.items():
print(f"{key}: {value}")
5. to_json_string function
- Write a function
to_json_string(obj)that takes an object and returns its JSON representation.
💡 Show Answer
import json
def to_json_string(obj):
return json.dumps(obj)
# Enhanced version with options
def to_json_string_enhanced(obj, pretty=False, sort_keys=False):
if pretty:
return json.dumps(obj, indent=2, sort_keys=sort_keys)
return json.dumps(obj, sort_keys=sort_keys)
# Test the functions
test_dict = {"name": "Alice", "age": 30, "city": "London"}
print(to_json_string(test_dict))
print(to_json_string_enhanced(test_dict, pretty=True))
# Function with error handling
def safe_to_json_string(obj):
try:
return json.dumps(obj)
except TypeError as e:
return f"Error: Cannot serialize object - {e}"
# Test with non-serializable object
import datetime
test_with_date = {"date": datetime.datetime.now()}
print(safe_to_json_string(test_with_date))
6. Pretty print JSON
- Use
json.dumps()with indentation to pretty-print a nested dictionary.
💡 Show Answer
import json
user = {
"id": 1,
"name": "Alice",
"address": {
"city": "Wonderland",
"zip": "12345",
"coordinates": {"lat": 40.7128, "lng": -74.0060}
},
"preferences": {
"theme": "dark",
"notifications": True,
"languages": ["en", "es", "fr"]
}
}
# Pretty print with different indentation
print("Indent 2:")
print(json.dumps(user, indent=2))
print("\nIndent 4:")
print(json.dumps(user, indent=4))
# With sorted keys
print("\nSorted keys:")
print(json.dumps(user, indent=2, sort_keys=True))
# Custom separators
print("\nCustom separators:")
print(json.dumps(user, indent=2, separators=(',', ': ')))
# Save to file with pretty printing
with open("user_pretty.json", "w") as f:
json.dump(user, f, indent=2, sort_keys=True)
7. Serialize object with non-serializable data
- Show what happens when you try to serialize a dictionary containing non-serializable objects.
💡 Show Answer
import json
from datetime import datetime
# Object with function (not serializable)
obj_with_function = {
"name": "Alice",
"greet": lambda: "Hello!" # Functions can't be serialized
}
try:
json.dumps(obj_with_function)
except TypeError as e:
print(f"Error with function: {e}")
# Object with datetime (not serializable by default)
obj_with_datetime = {
"name": "Alice",
"created_at": datetime.now()
}
try:
json.dumps(obj_with_datetime)
except TypeError as e:
print(f"Error with datetime: {e}")
# Solution: Custom JSON encoder
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
elif callable(obj):
return f"<function {obj.__name__}>"
return super().default(obj)
# Now it works
print("With custom encoder:")
print(json.dumps(obj_with_datetime, cls=CustomJSONEncoder, indent=2))
# Alternative: Convert before serializing
obj_converted = {
"name": "Alice",
"created_at": datetime.now().isoformat()
}
print(json.dumps(obj_converted, indent=2))
8. Compare types
- Demonstrate the difference between a dictionary and its JSON string using
type().
💡 Show Answer
import json
original_dict = {"name": "Alice", "age": 30}
json_string = json.dumps(original_dict)
print(f"Original type: {type(original_dict)}") # <class 'dict'>
print(f"JSON string type: {type(json_string)}") # <class 'str'>
print(f"Original: {original_dict}")
print(f"JSON: {json_string}")
# Show they're different but equivalent after parsing
parsed_back = json.loads(json_string)
print(f"Parsed back type: {type(parsed_back)}") # <class 'dict'>
print(f"Are they equal? {original_dict == parsed_back}") # True
# Memory usage comparison
import sys
print(f"Dict memory: {sys.getsizeof(original_dict)} bytes")
print(f"JSON memory: {sys.getsizeof(json_string)} bytes")
# Show string methods work on JSON
print(f"JSON length: {len(json_string)}")
print(f"Contains 'Alice': {'Alice' in json_string}")
9. Safe parse
- Write a function
safe_parse(json_str)that tries to parse JSON but handles errors if the string is invalid.
💡 Show Answer
import json
def safe_parse(json_str):
try:
return json.loads(json_str)
except json.JSONDecodeError:
return None
# Enhanced version with error details
def safe_parse_detailed(json_str):
try:
return {"success": True, "data": json.loads(json_str), "error": None}
except json.JSONDecodeError as e:
return {"success": False, "data": None, "error": str(e)}
# Test with valid JSON
valid_json = '{"name": "Alice", "age": 30}'
result = safe_parse(valid_json)
print(f"Valid JSON result: {result}")
# Test with invalid JSON
invalid_json = '{"name": "Alice", "age": 30' # Missing closing brace
result = safe_parse(invalid_json)
print(f"Invalid JSON result: {result}")
# Test detailed version
detailed_result = safe_parse_detailed(invalid_json)
print(f"Detailed result: {detailed_result}")
# More robust version with different error types
def robust_parse(json_str, default=None):
if not isinstance(json_str, str):
return default
try:
return json.loads(json_str)
except (json.JSONDecodeError, TypeError, ValueError) as e:
print(f"Parse error: {e}")
return default
# Test with various inputs
test_cases = [
'{"valid": true}',
'{"invalid": }',
None,
123,
'[]',
'[1, 2, 3]'
]
for test in test_cases:
result = robust_parse(test, {})
print(f"Input: {test} -> {result}")
10. Parse library JSON
- Create a JSON object for a
librarywith multiple books (title + author). - Parse it, loop through the books, and print each one.
💡 Show Answer
import json
# Method 1: Start with JSON string
library_json = '''
{
"name": "Central Library",
"location": "Downtown",
"books": [
{"title": "1984", "author": "George Orwell", "year": 1949},
{"title": "To Kill a Mockingbird", "author": "Harper Lee", "year": 1960},
{"title": "Pride and Prejudice", "author": "Jane Austen", "year": 1813}
]
}
'''
library = json.loads(library_json)
print(f"Library: {library['name']}")
print("Books:")
for book in library["books"]:
print(f"- '{book['title']}' by {book['author']} ({book['year']})")
# Method 2: Create dictionary first, then convert to JSON
library_dict = {
"name": "Public Library",
"books": [
{"title": "The Great Gatsby", "author": "F. Scott Fitzgerald"},
{"title": "1984", "author": "George Orwell"}
]
}
# Convert to JSON and back
library_json = json.dumps(library_dict, indent=2)
print(f"\nJSON representation:\n{library_json}")
# Parse back and iterate
parsed_library = json.loads(library_json)
for i, book in enumerate(parsed_library["books"], 1):
print(f"{i}. {book['title']} by {book['author']}")
# Working with files
def save_library(library_data, filename):
with open(filename, 'w') as f:
json.dump(library_data, f, indent=2)
def load_library(filename):
try:
with open(filename, 'r') as f:
return json.load(f)
except FileNotFoundError:
return {"name": "New Library", "books": []}
# Save and load example
save_library(library_dict, "library.json")
loaded_library = load_library("library.json")
print(f"\nLoaded from file: {loaded_library['name']}")
for book in loaded_library["books"]:
print(f"- {book['title']}")
# Search functionality
def find_books_by_author(library_data, author_name):
return [book for book in library_data["books"]
if author_name.lower() in book["author"].lower()]
# Find books by specific author
orwell_books = find_books_by_author(library, "Orwell")
print(f"\nBooks by Orwell: {orwell_books}")