Skip to main content

Lib/reprlib.py

Source:

cpython 3.14 @ ab2d84fe1023/Lib/reprlib.py

Map

LinesSymbolPurpose
1-20module headerimports, __all__
21-55recursive_repr()decorator that returns a fill string on re-entry
56-90Repr.__init__()limit attributes: maxlevel, maxdict, maxlist, maxlong, etc.
91-110Repr.repr(), Repr.repr1()public entry point and level-decrementing dispatcher
111-130Repr.repr_str(), Repr.repr_bytes()truncation helpers for scalar types
131-155Repr.repr_list(), Repr.repr_tuple(), Repr.repr_set(), Repr.repr_frozenset()sequence/set formatting with maxlevel guard
156-170Repr.repr_dict()sorted key iteration, pair formatting
171-175Repr.repr_instance()fallback for arbitrary instances
176-180module-level aRepr, reprsingleton and public alias

Reading

Repr class initialisation and limit attributes

Repr.__init__ sets a set of integer limit attributes that cap how many items are shown and how many characters are kept for scalar types. Each collection type has its own limit (maxdict, maxlist, maxset, maxtuple, maxarray, maxlong, maxstring), and maxlevel caps the recursion depth across all types.

# CPython: Lib/reprlib.py:56 Repr.__init__
def __init__(self):
self.maxlevel = 6
self.maxdict = 4
self.maxlist = 6
self.maxtuple = 6
self.maxset = 6
self.maxfrozenset = 6
self.maxdeque = 6
self.maxarray = 6
self.maxlong = 40
self.maxstring = 30
self.maxother = 30
self.fillvalue = '...'
self.indent = None

All attributes are plain integers on the instance so callers can override any limit by direct assignment after construction.

repr1 dispatch and maxlevel guard

repr1 is the recursive core. It decrements level on each call and returns self.fillvalue when it reaches zero, preventing unbounded recursion. The actual dispatch looks up repr_TYPE on self by building the method name from type(x).__name__.

# CPython: Lib/reprlib.py:99 Repr.repr1
def repr1(self, x, level):
typename = type(x).__name__
if ' ' in typename:
parts = typename.split()
typename = '_'.join(parts)
if level <= 0:
return self.fillvalue
methname = 'repr_' + typename
try:
meth = getattr(self, methname)
except AttributeError:
return self.repr_instance(x, level)
return meth(x, level)

Falling back to repr_instance when no typed handler exists means unknown types degrade gracefully rather than raising. Subclasses add support for new types simply by defining repr_mytypename methods.

recursive_repr decorator and cycle protection

recursive_repr wraps an instance method so that if the same object id is seen again while the method is already executing on that object, a fill string is returned immediately. It uses a per-invocation set stored on the wrapper closure.

# CPython: Lib/reprlib.py:21 recursive_repr
def recursive_repr(fillvalue='...'):
def decorating_function(user_function):
wrapper = _recursive_repr_wrapper(user_function, fillvalue)
return wrapper
return decorating_function

# CPython: Lib/reprlib.py:32 _recursive_repr_wrapper
def _recursive_repr_wrapper(user_function, fillvalue):
repr_running = set()
@functools.wraps(user_function)
def wrapper(self, *args, **kwargs):
key = id(self), get_ident()
if key in repr_running:
return fillvalue
repr_running.add(key)
try:
result = user_function(self, *args, **kwargs)
finally:
repr_running.discard(key)
return result
return wrapper

The key combines id(self) with the current thread id so that two threads can safely repr the same object concurrently without falsely triggering the cycle guard.

gopy notes

Status: not yet ported.

A port would live at module/reprlib/ in the gopy tree. The recursive_repr decorator requires working thread-local state (or a goroutine-id equivalent) and the functools.wraps machinery. The Repr class itself maps straightforwardly to a Go struct with integer fields and a method set. The module-level aRepr singleton and repr alias are a one-liner once the struct is in place. This port depends on module/functools/ being available for functools.wraps.