Python pprint — Core Concepts
What pprint provides
The pprint module formats Python data structures for human readability. It handles dicts, lists, tuples, sets, and nested combinations — the structures you stare at most during debugging.
Basic usage
from pprint import pprint
data = {"users": [{"name": "Alice", "roles": ["admin", "editor"]}, {"name": "Bob", "roles": ["viewer"]}], "count": 2}
pprint(data)
Output:
{'count': 2,
'users': [{'name': 'Alice', 'roles': ['admin', 'editor']},
{'name': 'Bob', 'roles': ['viewer']}]}
Compare this with print(data), which dumps everything on one line.
Key parameters
width (default: 80)
Controls the maximum line width before pprint breaks to the next line:
pprint(data, width=40) # narrower, more line breaks
pprint(data, width=200) # wider, fewer line breaks
If the entire structure fits within width, pprint keeps it on one line — it only expands when needed.
depth
Limits how deep into nested structures pprint will go. Deeper levels show as ...:
pprint(data, depth=1)
# {'count': 2, 'users': [...]}
Useful when you have deeply nested data and only care about the top level.
sort_dicts (Python 3.8+)
By default, pprint sorts dictionary keys alphabetically. Set sort_dicts=False to preserve insertion order:
pprint(data, sort_dicts=False)
compact (Python 3.3+)
When True, pprint tries to fit as many items as possible on each line (within width) instead of putting each on its own line:
pprint(list(range(20)), compact=True, width=40)
underscore_numbers (Python 3.10+)
Adds underscores to large numbers for readability:
pprint({"population": 8045311447}, underscore_numbers=True)
# {'population': 8_045_311_447}
PrettyPrinter class
For repeated use with the same settings, create an instance:
from pprint import PrettyPrinter
pp = PrettyPrinter(width=60, depth=3, sort_dicts=False)
pp.pprint(data)
# Get formatted string without printing
formatted = pp.pformat(data)
The pformat method returns the formatted string instead of printing it — useful for logging or writing to files.
pprint vs. json.dumps
Both can format nested data, but they serve different audiences:
| Feature | pprint | json.dumps(indent=2) |
|---|---|---|
| Python-native types | ✅ sets, tuples, custom objects | ❌ JSON types only |
| Valid Python syntax | ✅ output is eval-able | ❌ JSON syntax |
| Valid JSON output | ❌ | ✅ |
| Depth limiting | ✅ | ❌ |
| Handles circular refs | ✅ (shows <Recursion...>) | ❌ (raises error) |
Use pprint for debugging Python objects. Use json.dumps when you need actual JSON output.
Common misconception
pprint is sometimes mistaken for a serialization tool. It’s not — it’s a display tool. The output looks like Python code, but it’s not guaranteed to be valid Python in all cases (especially with custom objects). For serialization, use json, pickle, or similar.
One thing to remember
pprint shines during debugging and exploration. Reach for it whenever print() produces an unreadable wall of text, and remember pformat() when you need the string rather than stdout output.
See Also
- Python Atexit How Python's atexit module lets your program clean up after itself right before it shuts down.
- Python Bisect Sorted Lists How Python's bisect module finds things in sorted lists the way you'd find a word in a dictionary — by jumping to the middle.
- Python Contextlib How Python's contextlib module makes the 'with' statement work for anything, not just files.
- Python Copy Module Why copying data in Python isn't as simple as it sounds, and how the copy module prevents sneaky bugs.
- Python Dataclass Field Metadata How Python dataclass fields can carry hidden notes — like sticky notes on a filing cabinet that tools read automatically.