pprint
The pprint module provides functions to display Python data structures in a format that is easy to read. When you print a complex nested structure like a list of dictionaries, the default print() shows everything on one line. The pprint module formats these structures with line breaks and indentation so you can see the structure clearly.
This is useful when debugging, inspecting API responses, or logging complex data.
Functions
pp()
The main function for printing formatted output. Added in Python 3.8.
pp(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=False, underscore_numbers=False)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
object | any | — | The object to print |
stream | file-like | None | Output stream (defaults to stdout) |
indent | int | 1 | Spaces per indentation level |
width | int | 80 | Maximum characters per line |
depth | int | None | Maximum nesting depth (None = unlimited) |
compact | bool | False | Pack items on fewer lines when True |
sort_dicts | bool | False | Sort dictionary keys alphabetically |
underscore_numbers | bool | False | Add underscores as thousand separators |
Examples
import pprint
data = {
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
],
"count": 2
}
pprint.pp(data)
# {'count': 2,
# 'users': [{'age': 30, 'name': 'Alice'},
# {'age': 25, 'name': 'Bob'}]}
# Limit depth to see structure at a glance
pprint.pp(data, depth=1)
# {'count': 2, 'users': [modules::]}
pprint()
An alias for pp() with sort_dicts defaulting to True. Use this if you want dictionaries sorted by default.
pprint(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True, underscore_numbers=False)
Examples
import pprint
config = {"zebra": 1, "apple": 2, "mango": 3}
# pprint() sorts dict keys by default
pprint.pprint(config)
# {'apple': 2, 'mango': 3, 'zebra': 1}
# pp() preserves insertion order by default
pprint.pp(config)
# {'zebra': 1, 'apple': 2, 'mango': 3}
pformat()
Returns the formatted representation as a string instead of printing it.
pformat(object, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True, underscore_numbers=False)
Parameters
Same as pp().
Examples
import pprint
data = [{"id": i, "name": f"user_{i}"} for i in range(3)]
# Get formatted string for logging
log_line = pprint.pformat(data)
print(log_line)
# [{'id': 0, 'name': 'user_0'},
# {'id': 1, 'name': 'user_1'},
# {'id': 2, 'name': 'user_2'}]
# Use with custom width
short = pprint.pformat(data, width=40)
print(short)
# [{'id': 0, 'name': 'user_0'},
# {'id': 1, 'name': 'user_1'},
# {'id': 2, 'name': 'user_2'}]
isreadable()
Determines if the formatted representation can be used with eval() to recreate the object. Returns False for recursive structures or objects that cannot be reconstructed.
isreadable(object)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
object | any | — | The object to check |
Examples
import pprint
# Simple objects are readable
print(pprint.isreadable({"a": 1}))
# True
print(pprint.isreadable([1, 2, 3]))
# True
# Recursive structures are not readable
data = [1, 2]
data.append(data) # Self-referential
print(pprint.isreadable(data))
# False
isrecursive()
Determines if an object requires a recursive representation (contains a reference to itself).
isrecursive(object)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
object | any | — | The object to check |
Examples
import pprint
# Normal object
print(pprint.isrecursive([1, 2, 3]))
# False
# Self-referential list
data = [1, 2]
data.append(data)
print(pprint.isrecursive(data))
# True
# Recursive dictionary
d = {"key": None}
d["key"] = d
print(pprint.isrecursive(d))
# True
saferepr()
Returns a string representation that handles recursion safely. Instead of causing a RecursionError, it marks recursive references.
saferepr(object)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
object | any | — | The object to represent |
Examples
import pprint
# Normal object
print(pprint.saferepr([1, 2, 3]))
# [1, 2, 3]
# Recursive structure - safe!
data = ["hello"]
data.append(data)
print(pprint.saferepr(data))
# [<Recursion on list with id=...>, 'hello']
# Nested recursion
nested = {"self": None}
nested["self"] = nested
print(pprint.saferepr(nested))
# {'self': <Recursion on dict with id=...>}
PrettyPrinter Class
For repeated use with the same settings, create a PrettyPrinter instance.
pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, compact=False, sort_dicts=True, underscore_numbers=False)
Examples
import pprint
# Create a configured PrettyPrinter
pp = pprint.PrettyPrinter(indent=4, width=40, sort_dicts=True)
# Use it multiple times efficiently
data = {"players": [{"name": "Alice"}, {"name": "Bob"}]}
pp.pprint(data)
# { 'players': [ { 'name': 'Alice'},
# { 'name': 'Bob'}]}
# Access individual methods
formatted = pp.pformat(data)
print(pp.isreadable(data))
# True
Common Parameters
These parameters work across most pprint functions:
| Parameter | Type | Default | Description |
|---|---|---|---|
indent | int | 1 | Number of spaces for each indentation level |
width | int | 80 | Maximum characters per line before wrapping |
depth | int | None | Maximum nesting depth to display |
compact | bool | False | Pack items on fewer lines when True |
sort_dicts | bool | varies | Sort dictionary keys alphabetically |
Common Patterns
Debugging API responses
import pprint
import json
from urllib.request import urlopen
# Fetch and pretty-print JSON data
with urlopen('https://httpbin.org/json') as response:
data = json.load(response)
pprint.pp(data)
# {'slideshow': {'author': 'Yours Truly',
# 'date': 'date of publication',
# 'slides': [{'title': 'Wake up to WonderWidgets!',
# 'type': 'all'},
# {'': 'Why <em>WonderWidgets</em> are great',
# 'type': 'all'},
# {'': '', 'type': 'all'}],
# 'title': 'Sample Slide Show'}}
Logging complex data
import pprint
import logging
logging.basicConfig(level=logging.DEBUG)
class PrettyLogger:
def log(self, msg, data):
formatted = pprint.pformat(data, width=60)
logging.debug(f"{msg}:\n{formatted}")
logger = PrettyLogger()
logger.log("Request payload", {"headers": {"auth": "token"}, "body": {"query": "test"}})
# DEBUG:root:Request payload:
# DEBUG:root:{'body': {'query': 'test'},
# 'headers': {'auth': 'token'}}