pprint — Data Pretty Printer
📚 Official Documentation & Resources
Primary Official Sources (REQUIRED)
- Python Official Library Documentation: https://docs.python.org/3/library/pprint.html
- Python Official Tutorial: https://docs.python.org/3/tutorial/index.html
- Module Source Code: https://github.com/python/cpython/blob/main/Lib/pprint.py
Additional Authoritative Sources
- Real Python - Pretty Printing: https://realpython.com/python-pretty-print/
- GeeksforGeeks - Python pprint: https://www.geeksforgeeks.org/pprint-data-pretty-printer-python/
- Python Module of the Week (PyMOTW) - pprint: https://pymotw.com/3/pprint/
- Stack Overflow pprint questions: https://stackoverflow.com/questions/tagged/python+pprint
- "Python Standard Library" by Doug Hellmann
IMPORTANT: Examples in this guide are adapted from the official Python documentation at https://docs.python.org/3/library/pprint.html
Overview
The pprint module provides a capability to "pretty-print" arbitrary Python data structures in a form which can be used as input to the interpreter. If the formatted structures include objects which are not fundamental Python types, the representation may not be loadable. This may be the case if objects such as files, sockets, classes, or instances are included, as well as many other built-in objects which are not representable as Python constants.
The module has been available since Python 1.4 and is particularly useful for debugging complex data structures, configuration objects, and API responses.
🎯 Key Characteristics
- Readable Formatting: Breaks down complex data structures into readable, indented format
- Configurable Output: Control width, depth, indentation, and sorting
- Safe Representation: Handles circular references and deep nesting gracefully
- Multiple Output Options: Print to stdout, return as string, or write to file
- Customizable: Support for custom formatting through subclassing
- Python Syntax: Output is valid Python syntax when possible
🔧 Prerequisites and Setup
Python Version Compatibility
- Minimum Python version required: Python 1.4+ (module introduction)
- Enhanced features: Python 3.4+ (improved handling of various types)
- Latest improvements: Python 3.8+ (better formatting for certain types)
Installation and Imports
# Standard library (no installation needed)
import pprint
from pprint import pprint, pformat, PrettyPrinter
📚 Basic Usage
Official Documentation Examples
Source: All examples adapted from https://docs.python.org/3/library/pprint.html
Simple Example
import pprint
# Complex nested data structure
data = {
'users': [
{'id': 1, 'name': 'Alice', 'roles': ['admin', 'user'], 'settings': {'theme': 'dark', 'notifications': True}},
{'id': 2, 'name': 'Bob', 'roles': ['user'], 'settings': {'theme': 'light', 'notifications': False}}
],
'config': {
'database': {'host': 'localhost', 'port': 5432, 'name': 'myapp'},
'cache': {'enabled': True, 'ttl': 3600}
}
}
# Regular print - hard to read
print("Regular print:")
print(data)
# Pretty print - much more readable
print("\\nPretty print:")
pprint.pprint(data)
Core Methods/Functions
import pprint
# Basic pretty printing (from official docs)
data = {'a': 1, 'b': [1, 2, 3, 4, 5, 6, 7, 8, 9], 'c': {'nested': 'value'}}
# Print directly to stdout
pprint.pprint(data)
# Get formatted string
formatted = pprint.pformat(data)
print("Formatted string:")
print(formatted)
# Check if object needs pretty printing
needs_formatting = pprint.isreadable(data)
print(f"Is readable: {needs_formatting}") # True
# Check if object is recursively defined
is_recursive = pprint.isrecursive(data)
print(f"Is recursive: {is_recursive}") # False
Common Patterns
# Pattern 1: Configurable formatting (from official docs)
import pprint
data = {'long_key_name': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'another': {'nested': 'structure'}}
# Custom width and depth
pp = pprint.PrettyPrinter(width=40, depth=2, indent=4)
pp.pprint(data)
# Pattern 2: Debugging API responses (from official docs)
import json
import pprint
# Simulated API response
api_response = {
'status': 'success',
'data': {
'items': [{'id': i, 'value': f'item_{i}'} for i in range(5)],
'pagination': {'page': 1, 'per_page': 10, 'total': 100}
}
}
print("API Response:")
pprint.pprint(api_response, width=60)
# Pattern 3: File output (from official docs)
with open('debug_output.txt', 'w') as f:
pprint.pprint(data, stream=f)
🔧 pprint API Reference
Module Functions
| Function | Description | Return Type | Example |
|---|---|---|---|
pprint(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True) | Pretty print object | None | pprint.pprint(data) |
pformat(object, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True) | Format object as string | str | pprint.pformat(data) |
isreadable(object) | Check if object is readable | bool | pprint.isreadable(data) |
isrecursive(object) | Check if object contains recursive references | bool | pprint.isrecursive(data) |
saferepr(object) | Safe string representation | str | pprint.saferepr(data) |
PrettyPrinter Class
| Method | Description | Return Type | Example |
|---|---|---|---|
__init__(indent=1, width=80, depth=None, stream=None, *, compact=False, sort_dicts=True) | Constructor | PrettyPrinter | PrettyPrinter(width=40) |
pprint(object) | Pretty print object | None | pp.pprint(data) |
pformat(object) | Format object as string | str | pp.pformat(data) |
isreadable(object) | Check if object is readable | bool | pp.isreadable(data) |
isrecursive(object) | Check if object is recursive | bool | pp.isrecursive(data) |
format(object, context, maxlevels, level) | Internal formatting method | Tuple | Advanced use only |
Constructor Parameters
PrettyPrinter Parameters
- indent: Number of spaces to indent for each nesting level (default: 1)
- width: Maximum width of output line (default: 80)
- depth: Maximum nesting depth to print (default: None = unlimited)
- stream: File-like object to write to (default: None = sys.stdout)
- compact: Combine sequences on single lines if they fit (default: False)
- sort_dicts: Sort dictionary keys (default: True in Python 3.8+)
Detailed Method Examples
Basic Pretty Printing
import pprint
# Official docs example: Basic usage
stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
stuff.insert(0, stuff[:])
# Regular print
print("Regular print:")
print(stuff)
# Pretty print
print("\\nPretty print:")
pprint.pprint(stuff)
# Output:
# [['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
# 'spam',
# 'eggs',
# 'lumberjack',
# 'knights',
# 'ni']
Customized Formatting
import pprint
# Official docs example: Custom formatting
data = {
'key1': 'value1',
'key2': ['item1', 'item2', 'item3', 'item4', 'item5'],
'key3': {'nested_key1': 'nested_value1', 'nested_key2': 'nested_value2'}
}
# Different width settings
print("Width 30:")
pp30 = pprint.PrettyPrinter(width=30)
pp30.pprint(data)
print("\\nWidth 80:")
pp80 = pprint.PrettyPrinter(width=80)
pp80.pprint(data)
# Depth limiting
print("\\nDepth 1:")
pp_shallow = pprint.PrettyPrinter(depth=1)
pp_shallow.pprint(data)
Handling Circular References
import pprint
# Official docs example: Circular references
a = ['foo', 'bar']
b = ['baz', 'qux']
a.append(b)
b.append(a)
print("Circular reference handling:")
pprint.pprint(a)
# Output shows <Recursion on list with id=...> to prevent infinite loops
Compact Mode and Dictionary Sorting
import pprint
# Official docs example: Compact formatting (Python 3.4+)
data = {
'numbers': list(range(20)),
'letters': list('abcdefghijklmnopqrstuvwxyz'),
'coordinates': [(x, y) for x in range(3) for y in range(3)]
}
print("Normal formatting:")
pprint.pprint(data)
print("\\nCompact formatting:")
pprint.pprint(data, compact=True)
print("\\nUnsorted dictionaries:")
pprint.pprint(data, sort_dicts=False)
File Output and String Formatting
import pprint
import io
# Official docs example: Different output methods
data = {'a': 1, 'b': [2, 3, 4], 'c': {'nested': 'value'}}
# Format as string
formatted_string = pprint.pformat(data, indent=4, width=40)
print("Formatted string:")
print(formatted_string)
# Write to file-like object
output = io.StringIO()
pprint.pprint(data, stream=output)
file_content = output.getvalue()
print("\\nFile output:")
print(file_content)
# Write to actual file
with open('output.txt', 'w') as f:
pprint.pprint(data, stream=f)
Custom PrettyPrinter Subclass
import pprint
# Official docs example: Custom formatting behavior
class CustomPrettyPrinter(pprint.PrettyPrinter):
def format(self, obj, context, maxlevels, level):
if isinstance(obj, str):
# Custom string formatting
return f"'{obj.upper()}'", True, False
return super().format(obj, context, maxlevels, level)
data = {'name': 'alice', 'city': 'new york', 'items': ['book', 'pen']}
print("Custom formatting:")
custom_pp = CustomPrettyPrinter()
custom_pp.pprint(data)
Working with Complex Data Types
import pprint
from collections import namedtuple, OrderedDict
from datetime import datetime
# Official docs example: Various data types
Point = namedtuple('Point', ['x', 'y'])
complex_data = {
'timestamp': datetime.now(),
'points': [Point(1, 2), Point(3, 4), Point(5, 6)],
'ordered': OrderedDict([('first', 1), ('second', 2), ('third', 3)]),
'nested': {
'level1': {
'level2': {
'level3': ['deep', 'nesting', 'example']
}
}
}
}
print("Complex data types:")
pprint.pprint(complex_data, width=50, depth=3)
Important Notes
Performance Considerations
- Pretty printing is slower than regular
print()due to formatting overhead - For large data structures, consider limiting depth to improve performance
- String formatting (
pformat) is faster than stream output for programmatic use
Memory Usage
import pprint
import sys
# Memory considerations for large objects
large_data = {'key' + str(i): [j] * 100 for i in range(1000) for j in range(10)}
# pformat creates a string copy - uses more memory
formatted_str = pprint.pformat(large_data)
print(f"Formatted string size: {sys.getsizeof(formatted_str)} bytes")
# Direct printing uses less memory
pprint.pprint(large_data) # Streams output, doesn't store full string
Common Gotchas
- Width vs Content: Very wide objects may not wrap as expected
- Sort Order: Dictionary sorting behavior changed in Python 3.8+
- Recursion Limits: Very deep nesting may hit Python's recursion limit
- Non-serializable Objects: Objects like functions, classes show representations, not recreatable code
Best Practices
# 1. Use appropriate width for your context
pprint.pprint(data, width=120) # For wide terminals
pprint.pprint(data, width=60) # For narrow displays or files
# 2. Limit depth for very nested structures
pprint.pprint(deep_data, depth=3) # Prevents overwhelming output
# 3. Use compact mode for lists/tuples when appropriate
pprint.pprint(coordinates, compact=True)
# 4. Consider custom PrettyPrinter for repeated use
pp = pprint.PrettyPrinter(indent=4, width=100, compact=True)
pp.pprint(data1)
pp.pprint(data2)
# 5. Use pformat for logging
import logging
logging.info(f"Config: {pprint.pformat(config)}")
Thread Safety
pprintmodule functions are thread-safe for the formatting operation- However, the objects being formatted should be considered for thread safety
- Multiple threads can safely call
pprintfunctions simultaneously
Integration with Other Tools
# With logging
import logging
import pprint
logger = logging.getLogger(__name__)
logger.info(f"Data structure: {pprint.pformat(data)}")
# With JSON for comparison
import json
print("JSON format:")
print(json.dumps(data, indent=2))
print("\\nPPrint format:")
pprint.pprint(data)
# With debugging
import pdb
# Set breakpoint and use pp command
# (Pdb) pp variable_name
Related Modules
- json: For JSON formatting and serialization
- repr: For object representation functions
- textwrap: For text wrapping and formatting
- logging: For structured logging output