Python pprint: Make Nested Data Actually Readable
The Problem
I was debugging an API response the other day, and I got this:
response = { "users": [ {"id": 1, "name": "Alice", "roles": ["admin", "editor"], "settings": {"theme": "dark", "notifications": True}}, {"id": 2, "name": "Bob", "roles": ["viewer"], "settings": {"theme": "light", "notifications": False}} ], "metadata": {"total": 2, "page": 1, "per_page": 10}}
print(response)The output was a nightmare:
{'users': [{'id': 1, 'name': 'Alice', 'roles': ['admin', 'editor'], 'settings': {'theme': 'dark', 'notifications': True}}, {'id': 2, 'name': 'Bob', 'roles': ['viewer'], 'settings': {'theme': 'light', 'notifications': False}}], 'metadata': {'total': 2, 'page': 1, 'per_page': 10}}One long line. No indentation. Impossible to read. I had to copy it to an online formatter just to understand the structure.
Then I remembered: Python has a built-in module for this.
The Solution: pprint
Python’s pprint module is designed exactly for this problem. It formats complex data structures with proper indentation and line breaks.
from pprint import pprint
response = { "users": [ {"id": 1, "name": "Alice", "roles": ["admin", "editor"], "settings": {"theme": "dark", "notifications": True}}, {"id": 2, "name": "Bob", "roles": ["viewer"], "settings": {"theme": "light", "notifications": False}} ], "metadata": {"total": 2, "page": 1, "per_page": 10}}
pprint(response)Now the output looks like this:
{'metadata': {'page': 1, 'per_page': 10, 'total': 2}, 'users': [{'id': 1, 'name': 'Alice', 'roles': ['admin', 'editor'], 'settings': {'notifications': True, 'theme': 'dark'}}, {'id': 2, 'name': 'Bob', 'roles': ['viewer'], 'settings': {'notifications': False, 'theme': 'light'}}]}Suddenly I can see the structure. Each level is indented. Dictionary keys are sorted alphabetically. Lists break across lines when they get long.
When to Use pprint vs print
I reach for pprint when I’m dealing with:
- API responses (JSON converted to dicts)
- Configuration files loaded into Python
- Database query results
- Nested data structures in general
- Debugging complex objects
Regular print() is fine for simple things:
# print() is fine for simple outputname = "Alice"count = 42print(f"User {name} has {count} items") # Perfectly readableBut once I have nested structures, print() fails me:
# print() struggles with nested dataconfig = { "database": { "host": "localhost", "port": 5432, "credentials": {"user": "admin", "password": "secret"} }, "cache": { "backend": "redis", "servers": ["redis1", "redis2", "redis3"] }}
print(config) # One line messpprint(config) # Readable structureGetting the Formatted String: pformat()
Sometimes I don’t want to print directly. I want to capture the formatted string for logging or further processing.
pprint.pprint() prints to stdout, but pprint.pformat() returns a string:
from pprint import pformat
config = { "database": { "host": "localhost", "port": 5432, "credentials": {"user": "admin", "password": "secret"} }}
# Returns a string instead of printingformatted = pformat(config)
# Now I can use it however I wantlog_message = f"Loaded config:\n{formatted}"print(log_message)
# Or save to filewith open("config_dump.txt", "w") as f: f.write(formatted)This is useful when:
- Logging to a file
- Building error messages
- Storing debug output
- Testing (comparing formatted strings)
Controlling the Output Width
By default, pprint tries to fit things in 80 characters. I can change that:
from pprint import pprint
data = {"items": ["apple", "banana", "cherry", "date", "elderberry"]}
# Default width (80 characters)pprint(data)# {'items': ['apple', 'banana', 'cherry', 'date', 'elderberry']}
# Narrow width - forces more line breakspprint(data, width=40)# {'items': ['apple',# 'banana',# 'cherry',# 'date',# 'elderberry']}
# Wide width - fits more on one linepprint(data, width=120)# {'items': ['apple', 'banana', 'cherry', 'date', 'elderberry']}The width parameter controls when pprint decides to wrap lines.
Controlling Indentation and Depth
When I have deeply nested data, I can control how deep to go:
from pprint import pprint
deeply_nested = { "level1": { "level2": { "level3": { "level4": { "value": "deep" } } } }}
# Limit depth to 2 levelspprint(deeply_nested, depth=2)# {'level1': {'level2': {...}}}The {...} shows that pprint stopped at that depth. This is helpful when I only care about the top-level structure.
I can also control indentation:
from pprint import pprint
data = {"users": [{"name": "Alice"}, {"name": "Bob"}]}
# Default indent (1 space)pprint(data)# {'users': [{'name': 'Alice'}, {'name': 'Bob'}]}
# Custom indent (4 spaces)pprint(data, indent=4)# { 'users': [ {'name': 'Alice'},# {'name': 'Bob'}]}A Real Debugging Workflow
Here’s how I use pprint in actual debugging:
import jsonfrom pprint import pprint
# 1. Load some dataresponse = '{"status": "ok", "data": {"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}], "count": 2}}'data = json.loads(response)
# 2. Quick check - what's the structure?pprint(data)# {'data': {'count': 2, 'users': [{'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}]}, 'status': 'ok'}
# 3. Something's wrong - let me check a specific partpprint(data["data"]["users"])# [{'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}]
# 4. Need more detail on one item?pprint(data["data"]["users"][0], width=40)# {'id': 1, 'name': 'Alice'}The key insight: I use pprint as a quick “what does this look like?” tool. No need to copy-paste into formatters or add print statements with manual formatting.
pprint vs json.dumps for Formatting
I used to use json.dumps with indent for formatting:
import json
data = {"name": "Alice", "items": [1, 2, 3]}
# Using json.dumpsprint(json.dumps(data, indent=2))# {# "name": "Alice",# "items": [# 1,# 2,# 3# ]# }But json.dumps has limitations:
- Only works with JSON-serializable types (no sets, tuples, custom objects)
- Changes types (tuples become lists)
- Fails on things like
datetimeobjects
from pprint import pprintimport json
data = { "items": {1, 2, 3}, # Set - not JSON serializable "coords": (10, 20), # Tuple "name": "test"}
# json.dumps fails# json.dumps(data) # TypeError: Object of type set is not JSON serializable
# pprint handles it finepprint(data)# {'coords': (10, 20), 'items': {1, 2, 3}, 'name': 'test'}I use pprint for debugging Python objects and json.dumps when I specifically need JSON output.
Summary
Python’s pprint module solves the “unreadable nested data” problem with zero dependencies:
pprint(data)prints formatted output to stdoutpformat(data)returns the formatted stringwidthcontrols line lengthdepthlimits how deep to formatindentcontrols indentation spacing
The next time I’m debugging an API response or complex data structure, I reach for pprint instead of struggling with one-liner print() output. It’s built into Python, requires no installation, and saves me from copy-pasting into online formatters.
from pprint import pprint, pformat
# Quick printpprint(data)
# Get as stringformatted = pformat(data)
# Control formattingpprint(data, width=60, indent=2, depth=3)One import, instant readability.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments