The pprint module formats complex data structures for human readability. Essential for debugging nested dicts, lists, and API responses.

Basic pprint

from pprint import pprint
 
data = {
    "users": [
        {"name": "Alice", "email": "alice@example.com", "roles": ["admin", "user"]},
        {"name": "Bob", "email": "bob@example.com", "roles": ["user"]},
    ],
    "metadata": {"version": "1.0", "generated": "2024-01-15"},
}
 
# Regular print: hard to read
print(data)
# {'users': [{'name': 'Alice', 'email': 'alice@example.com', 'roles': ['admin', 'user']}, ...
 
# pprint: formatted
pprint(data)
# {'metadata': {'generated': '2024-01-15', 'version': '1.0'},
#  'users': [{'email': 'alice@example.com',
#             'name': 'Alice',
#             'roles': ['admin', 'user']},
#            {'email': 'bob@example.com',
#             'name': 'Bob',
#             'roles': ['user']}]}

pformat: Get String Instead of Print

from pprint import pformat
 
data = {"a": [1, 2, 3], "b": {"nested": True}}
 
formatted = pformat(data)
# Now you can log it, save it, etc.
print(formatted)

Width Control

from pprint import pprint
 
data = ["item1", "item2", "item3", "item4", "item5"]
 
# Default width (80)
pprint(data)
# ['item1', 'item2', 'item3', 'item4', 'item5']
 
# Narrow width forces wrapping
pprint(data, width=30)
# ['item1',
#  'item2',
#  'item3',
#  'item4',
#  'item5']

Depth Limits

from pprint import pprint
 
deep = {"a": {"b": {"c": {"d": {"e": "deep"}}}}}
 
# Full depth
pprint(deep)
# {'a': {'b': {'c': {'d': {'e': 'deep'}}}}}
 
# Limited depth
pprint(deep, depth=2)
# {'a': {'b': {...}}}

Compact Mode

from pprint import pprint
 
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 
# Normal: each element on new line if doesn't fit
pprint(data, width=20)
# [1,
#  2,
#  3,
#  ...
 
# Compact: fit as many as possible per line
pprint(data, width=20, compact=True)
# [1, 2, 3, 4, 5,
#  6, 7, 8, 9, 10]

Sorting Keys

from pprint import pprint
 
data = {"zebra": 1, "apple": 2, "mango": 3}
 
# Default: sorted keys
pprint(data)
# {'apple': 2, 'mango': 3, 'zebra': 1}
 
# Preserve insertion order (Python 3.8+)
pprint(data, sort_dicts=False)
# {'zebra': 1, 'apple': 2, 'mango': 3}

PrettyPrinter Class

For repeated formatting with same settings:

from pprint import PrettyPrinter
 
pp = PrettyPrinter(
    indent=2,
    width=60,
    depth=3,
    compact=True,
    sort_dicts=False,
)
 
pp.pprint(data)
 
# Get formatted string
formatted = pp.pformat(data)

Stream Output

from pprint import pprint
import sys
 
# Print to stderr
pprint(data, stream=sys.stderr)
 
# Print to file
with open("debug.txt", "w") as f:
    pprint(data, stream=f)

Practical Examples

Debug Logger

from pprint import pformat
import logging
 
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
 
def debug_data(label: str, data):
    logger.debug(f"{label}:\n{pformat(data)}")
 
response = {"status": 200, "data": [1, 2, 3]}
debug_data("API Response", response)

API Response Inspection

from pprint import pprint
import requests
 
def inspect_response(url: str):
    response = requests.get(url)
    print(f"Status: {response.status_code}")
    print("Headers:")
    pprint(dict(response.headers), depth=1)
    print("Body:")
    pprint(response.json(), depth=2)

Config File Dump

from pprint import pformat
 
def save_config(config: dict, path: str):
    with open(path, "w") as f:
        f.write("# Generated config\n")
        f.write(f"config = {pformat(config)}\n")

REPL Enhancement

import sys
from pprint import pprint
 
# Make pprint the default display in REPL
sys.displayhook = lambda x: pprint(x) if x is not None else None

Comparison: print vs pprint vs json.dumps

import json
from pprint import pprint
 
data = {"key": [1, 2, {"nested": True}]}
 
# print: single line, no formatting
print(data)
# {'key': [1, 2, {'nested': True}]}
 
# pprint: Python-formatted, readable
pprint(data)
# {'key': [1, 2, {'nested': True}]}
 
# json.dumps: JSON-formatted
print(json.dumps(data, indent=2))
# {
#   "key": [
#     1,
#     2,
#     {"nested": true}
#   ]
# }

Use pprint for Python debugging, json.dumps for JSON output.

Quick Reference

from pprint import pprint, pformat, PrettyPrinter
 
# Print formatted
pprint(obj)
pprint(obj, width=80, depth=None, compact=False)
 
# Get formatted string
s = pformat(obj)
 
# Reusable printer
pp = PrettyPrinter(indent=1, width=80, depth=None, compact=False)
pp.pprint(obj)
pp.pformat(obj)
ParameterDefaultPurpose
width80Line width before wrapping
depthNoneMax nesting depth
indent1Indentation per level
compactFalsePack items densely
sort_dictsTrueSort dict keys
streamstdoutOutput destination

pprint is simple but essential. Use it whenever you need to see what's actually in your data.

React to this post: