pprint

Updated March 13, 2026 · Modules
stdlib output debugging formatting

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

ParameterTypeDefaultDescription
objectanyThe object to print
streamfile-likeNoneOutput stream (defaults to stdout)
indentint1Spaces per indentation level
widthint80Maximum characters per line
depthintNoneMaximum nesting depth (None = unlimited)
compactboolFalsePack items on fewer lines when True
sort_dictsboolFalseSort dictionary keys alphabetically
underscore_numbersboolFalseAdd 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

ParameterTypeDefaultDescription
objectanyThe 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

ParameterTypeDefaultDescription
objectanyThe 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

ParameterTypeDefaultDescription
objectanyThe 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:

ParameterTypeDefaultDescription
indentint1Number of spaces for each indentation level
widthint80Maximum characters per line before wrapping
depthintNoneMaximum nesting depth to display
compactboolFalsePack items on fewer lines when True
sort_dictsboolvariesSort 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'}}

See Also