Web Analytics

JSON Module

Intermediate ~25 min read

JSON (JavaScript Object Notation) is the universal language of data exchange on the web. APIs return JSON, configuration files use JSON, and databases store JSON. Python's built-in json module makes it easy to parse JSON strings into Python dictionaries, convert Python objects to JSON, and read/write JSON files. If you're building web applications, working with APIs, or handling configuration data - JSON mastery is essential!

Parsing JSON (String to Python)

Use json.loads() ("load string") to parse a JSON string into a Python object. JSON objects become Python dictionaries, arrays become lists, and JSON's true, false, and null become Python's True, False, and None.

Output
Click Run to execute your code
JSON Type Mapping:
JSON object {} โ†’ Python dict
JSON array [] โ†’ Python list
JSON string โ†’ Python str
JSON number โ†’ Python int or float
JSON true/false โ†’ Python True/False
JSON null โ†’ Python None

Converting Python to JSON

Use json.dumps() ("dump string") to convert Python objects to a JSON string. Most Python types convert naturally: dictionaries become objects, lists/tuples become arrays, and booleans/None convert to their JSON equivalents. Some types (like sets and datetime) require custom handling.

Output
Click Run to execute your code
Remember the 's' suffix: loads() and dumps() work with strings (the 's' stands for string). load() and dump() (without 's') work with files. This naming convention helps you remember which function to use!

Reading and Writing JSON Files

Use json.load() to read JSON from a file and json.dump() to write JSON to a file. These work directly with file objects, making it easy to persist data or read configuration files. Always use the with statement to ensure proper file handling.

Output
Click Run to execute your code
JSON File Safety: Always validate JSON from untrusted sources. While json.loads() is safer than eval(), malformed JSON can still cause errors. Wrap parsing in try/except blocks: try: data = json.loads(text) except json.JSONDecodeError: handle_error()

Formatting and Pretty Printing

By default, json.dumps() produces compact output. For human-readable output, use indent for pretty printing and sort_keys for consistent key ordering. These options are invaluable for debugging, logging, and configuration files.

Output
Click Run to execute your code

Common Mistakes

1. Confusing loads/dumps with load/dump

import json

# Wrong - loads expects a string, not a file!
with open("data.json") as f:
    data = json.loads(f)  # TypeError!

# Correct - use load (no 's') for files
with open("data.json") as f:
    data = json.load(f)

# Wrong - dumps returns a string, doesn't write to file
with open("out.json", "w") as f:
    json.dumps(data, f)  # Just returns string, ignores f!

# Correct - use dump (no 's') for files
with open("out.json", "w") as f:
    json.dump(data, f)

2. Using single quotes in JSON strings

import json

# Wrong - JSON requires double quotes!
bad_json = "{'name': 'Alice'}"
data = json.loads(bad_json)  # JSONDecodeError!

# Correct - use double quotes
good_json = '{"name": "Alice"}'
data = json.loads(good_json)  # Works!

# Tip: Use triple quotes for multiline JSON
json_str = """
{
    "name": "Alice",
    "age": 30
}
"""

3. Trying to serialize non-JSON types

import json
from datetime import datetime

# Wrong - sets and datetime aren't JSON serializable!
data = {
    "tags": {"python", "json"},  # set
    "created": datetime.now()     # datetime
}
json.dumps(data)  # TypeError!

# Fix 1: Convert to serializable types
data = {
    "tags": list({"python", "json"}),
    "created": datetime.now().isoformat()
}

# Fix 2: Use custom encoder
def custom_encoder(obj):
    if isinstance(obj, set):
        return list(obj)
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Not serializable: {type(obj)}")

json.dumps(data, default=custom_encoder)

4. Not handling JSONDecodeError

import json

# Wrong - crashes on invalid JSON
user_input = "not valid json"
data = json.loads(user_input)  # JSONDecodeError!

# Correct - handle the error
try:
    data = json.loads(user_input)
except json.JSONDecodeError as e:
    print(f"Invalid JSON: {e}")
    data = {}  # Default value

5. Forgetting to specify encoding for non-ASCII

import json

# Unicode characters
data = {"name": "Caf\u00e9", "city": "Z\u00fcrich"}

# Default - escapes non-ASCII (safe but ugly)
print(json.dumps(data))
# {"name": "Caf\u00e9", "city": "Z\u00fcrich"}

# Better for readability - preserve unicode
print(json.dumps(data, ensure_ascii=False))
# {"name": "Caf", "city": "Zrich"}

# When writing files - specify encoding!
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False)

Exercise: Configuration Manager

Task: Create functions to manage application configuration stored as JSON.

Requirements:

  • Create a function to load config from a JSON string
  • Create a function to get a config value with a default
  • Create a function to update config and return the JSON string
  • Handle missing keys gracefully
Output
Click Run to execute your code
Show Solution
import json

def load_config(json_string):
    """Load configuration from JSON string."""
    try:
        return json.loads(json_string)
    except json.JSONDecodeError:
        return {}

def get_config_value(config, key, default=None):
    """Get a configuration value with optional default."""
    return config.get(key, default)

def update_config(config, key, value):
    """Update config and return as formatted JSON string."""
    config[key] = value
    return json.dumps(config, indent=2)

# Test the functions
config_json = '{"theme": "dark", "font_size": 14}'

# Load
config = load_config(config_json)
print(f"Loaded: {config}")

# Get values
theme = get_config_value(config, "theme", "light")
language = get_config_value(config, "language", "en")
print(f"Theme: {theme}")
print(f"Language: {language}")

# Update
new_json = update_config(config, "notifications", True)
print(f"Updated config:\n{new_json}")

Summary

  • Parse string: json.loads(json_string) - JSON string to Python
  • Encode to string: json.dumps(python_obj) - Python to JSON string
  • Read file: json.load(file_object) - file to Python
  • Write file: json.dump(python_obj, file_object) - Python to file
  • Pretty print: json.dumps(data, indent=2)
  • Sort keys: json.dumps(data, sort_keys=True)
  • Custom types: json.dumps(data, default=encoder_func)
  • Error handling: Catch json.JSONDecodeError for invalid JSON

What's Next?

Now that you can work with JSON data, let's learn about Regular Expressions (RegEx) - the powerful pattern matching language for searching, validating, and manipulating text. RegEx is essential for data validation, text processing, and parsing complex string patterns!