Skip to main content

pprint.py: Pretty-Printer Internals

cpython 3.14 @ ab2d84fe1023/

pprint provides a PrettyPrinter class that formats Python objects into human-readable multi-line text. The 3.14 release added underscore_numbers support and a new depth sentinel so callers can distinguish "not set" from zero.

Map

LinesSymbolKindNotes
1-30module headersetupimports, __all__, version note
32-60pprintfunctionthin wrapper around PrettyPrinter.pprint
62-80pformatfunctionreturns formatted string, no newline
82-95ppfunction3.8+ shorthand, sort_dicts=False default
97-120isreadablefunctiondelegates to _safe_repr readability flag
122-145isrecursivefunctiondelegates to _safe_repr recursion flag
147-220PrettyPrinter.__init__methodvalidates indent, width, depth, compact, sort_dicts, underscore_numbers
221-260PrettyPrinter.pprintmethodformats then writes to stream
261-290PrettyPrinter.pformatmethodcalls _format, returns string
291-350PrettyPrinter._formatmethoddispatch on object type, indentation logic
351-430PrettyPrinter._pprint_dictmethodsorts keys when sort_dicts=True
431-480PrettyPrinter._pprint_listmethodcompact mode, wraps at width
481-520PrettyPrinter._pprint_tuplemethodmirrors list logic, trailing comma on singleton
521-560_safe_reprfunctionrecursive repr with cycle detection
561-600_recursion, _wrap_bytes_reprhelperssentinel string, bytes chunker

Reading

Entry points

The three public entry points delegate immediately to a throw-away PrettyPrinter instance. pp fixes sort_dicts=False so insertion order is preserved, which is the ergonomic default since Python 3.7 dicts became ordered.

# Lib/pprint.py:32
def pprint(object, stream=None, indent=1, width=80, depth=None, *,
compact=False, sort_dicts=True, underscore_numbers=False):
printer = PrettyPrinter(
stream=stream, indent=indent, width=width, depth=depth,
compact=compact, sort_dicts=sort_dicts,
underscore_numbers=underscore_numbers)
printer.pprint(object)

# Lib/pprint.py:82
def pp(object, *args, sort_dicts=False, **kwargs):
pprint(object, *args, sort_dicts=sort_dicts, **kwargs)

_safe_repr recursive formatter

_safe_repr is the heart of the module. It carries three return values: the repr string, a readable flag, and a recursive flag. Cycle detection uses an allowance dict keyed by id(object).

# Lib/pprint.py:521
def _safe_repr(object, context, maxlevels, level, sort_dicts):
typ = type(object)
if typ in _builtin_scalars:
return repr(object), True, False

r = getattr(typ, "__repr__", None)
# ... cycle guard ...
objid = id(object)
if objid in context:
return _recursion(object), False, True
context[objid] = 1
# ... recurse into containers ...
del context[objid]
return repr_string, readable, recursive

PrettyPrinter._format dispatch

_format checks whether the repr fits on the current line. If it does, it emits it inline. Otherwise it dispatches to a type-specific _pprint_* method via the _dispatch table built at class definition time.

# Lib/pprint.py:291
def _format(self, object, stream, indent, allowance, context, level):
objid = id(object)
if objid in context:
stream.write(_recursion(object))
...
return
rep = self._repr(object, context, level)
max_width = self._width - indent - allowance
if len(rep) <= max_width:
stream.write(rep)
return
p = self._dispatch.get(type(object).__repr__, None)
if p is not None:
context[objid] = 1
p(self, object, stream, indent, allowance, context, level + 1)
del context[objid]
else:
stream.write(rep)

gopy notes

  • _safe_repr must be ported as a standalone Go function; it is not a method.
  • The _dispatch class-level dict maps __repr__ method objects to handler functions. In Go this becomes a map[reflect.Type]formatFunc keyed on the Go type.
  • underscore_numbers calls format(n, '_') internally. The gopy format builtin must support the underscore grouping option before this module can pass its test suite.
  • compact mode for lists and tuples requires measuring tentative line lengths before committing to write, so buffering is needed.