The reprlib module produces abbreviated representations of Python objects. Instead of printing a list with millions of elements, an enormous string, or a deeply nested structure, it limits length, item count, and depth. This is useful in logs, consoles, debuggers, error messages, inspection tools, and administrative interfaces.
A shortened representation is not serialization. It is intended for people and diagnostics, not object reconstruction. It can also reveal sensitive data when an object’s repr() exposes it. Size limits reduce volume but do not replace redaction, access control, or a logging policy.
repr and reprlib
The built-in repr() function tries to create an unambiguous developer-oriented representation.
data = list(range(1000))
print(repr(data))
For large objects, the result can consume memory, flood logs, and hide relevant details. reprlib.repr() uses a default Repr instance to abbreviate it.
import reprlib
print(reprlib.repr(data))
Supported types
The implementation understands common types such as strings, bytes, lists, tuples, sets, frozensets, dictionaries, arrays, and generic objects. Containers are limited by item count and text by character count.
Custom objects still depend on their own __repr__() unless you create a specialized representation policy.
Create a Repr instance
The Repr class exposes attributes that control limits.
from reprlib import Repr
summary = Repr()
summary.maxlist = 5
summary.maxstring = 40
summary.maxdict = 4
print(summary.repr(data))
Use one instance per presentation policy. An interactive console may allow more detail than a production log.
List limits
maxlist controls how many list items appear. The module selects a limited set and inserts an ellipsis to indicate omitted content.
The representation does not necessarily state how many items were hidden. Log len(value) separately when total size matters.
Tuples
maxtuple controls tuple output. A one-item tuple keeps the comma required to represent its shape.
summary.maxtuple = 3
print(summary.repr(tuple(range(20))))
Never parse abbreviated output with eval(). Ellipses and truncation mean the text may not be a complete expression.
Sets and frozensets
maxset and maxfrozenset limit set-like collections. Sets do not have a stable semantic order, so the visible sample can vary.
Do not use this output as a deterministic snapshot across machines. For tests, normalize a derived collection when elements can be sorted.
Dictionaries
maxdict limits key-value pairs.
summary.maxdict = 3
config = {f"key_{i}": i for i in range(20)}
print(summary.repr(config))
A sensitive key may still appear in a small sample. Redact or filter the mapping before representation.
Strings
maxstring controls string length.
summary.maxstring = 30
print(summary.repr("a" * 500))
Abbreviation usually preserves portions of the beginning and end. That is useful for paths and identifiers, but it can expose secret prefixes and suffixes.
Long output from custom objects
Additional limits such as maxlong affect selected representation paths. Exact behavior depends on type and Python version.
Test the real objects used by the application. One attribute does not automatically constrain every custom __repr__().
Bytes and binary values
String-related limits also affect several bytes representations. Binary payloads can contain tokens, personal data, or control bytes.
For payload diagnostics, prefer size, a digest, and an explicitly sanitized sample.
Other containers
Attributes such as maxarray, maxdeque, and maxother control additional categories. Consult the Python version used by the project for the complete set.
Setting very large limits removes practical protection against log explosions.
Depth with maxlevel
maxlevel limits nested traversal.
summary.maxlevel = 2
nested = {"a": {"b": {"c": {"d": 1}}}}
print(summary.repr(nested))
This prevents a diagnostic operation from walking an enormous object tree.
Recursive objects
A container may refer to itself.
items = []
items.append(items)
print(repr(items))
Python’s representation system detects several cycles. reprlib adds limits, but a custom __repr__() can still recurse indefinitely when it lacks protection.
recursive_repr
The recursive_repr() decorator protects a custom __repr__() against recursion.
from reprlib import recursive_repr
class Node:
def __init__(self, value):
self.value = value
self.next = None
@recursive_repr(fillvalue="...")
def __repr__(self):
return f"Node({self.value!r}, next={self.next!r})"
When the same object is reached again in the same representation thread, the decorator returns the marker.
Choosing fillvalue
The fillvalue argument defines the recursion marker. Keep it short and clearly artificial.
Do not choose text that could be mistaken for real application data.
Subclass Repr
A subclass can customize selected application types.
from reprlib import Repr
class ApplicationRepr(Repr):
def repr_User(self, obj, level):
return f"User(id={obj.id!r})"
Test dispatch carefully because inheritance, dynamic classes, and qualified names may require another strategy.
Redact before formatting
Objects containing passwords, tokens, keys, and personal data should be sanitized first.
def sanitize(config):
hidden = {"password", "token", "secret"}
return {
key: "***" if key.lower() in hidden else value
for key, value in config.items()
}
Apply reprlib to the sanitized structure. Truncation alone is not secrecy.
Structured logging
In JSON logging, separate fields such as type, length, item count, and sample are usually better than one representation string.
reprlib can generate the sample, while metadata remains searchable and controlled by the observability pipeline.
Error messages
An exception can include a bounded summary of an invalid value.
short_value = summary.repr(value)
raise ValueError(f"invalid value: {short_value}")
Escape untrusted input when the message will be rendered in HTML, a styled terminal, or another interpreted context.
Control characters
Strings may contain terminal controls. repr() escapes many characters, but output surfaces still need appropriate handling.
Never write arbitrary binary payloads directly to a human terminal. Use a bounded textual representation.
Performance
Limiting final output reduces text size, but selected objects still have their __repr__() called. A custom representation can be slow, access a network, or cause side effects, all of which are poor design.
__repr__() should be fast, safe, and side-effect free.
Lazy objects
Do not materialize generators or iterators merely to represent them. That can consume a stream and change program behavior.
Record type, known state, and an identifier instead. Safe diagnostics should not force expensive computation.
Dataclasses
Dataclasses generate __repr__() automatically. Sensitive fields can use repr=False.
from dataclasses import dataclass, field
@dataclass
class Credential:
username: str
password: str = field(repr=False)
Combine this with redaction because nested objects may still reveal information.
Format stability
Representations of internal types can change between Python releases. Do not use human-oriented repr output as a protocol, cache key, signature, or persistent format.
Use JSON, a database, or another versioned format for persistence.
Snapshot tests
Snapshots based on repr can be fragile because of set ordering, memory addresses, and version changes. Normalize data and remove unstable values first.
Test below, at, and above each configured limit.
Designing __repr__
A good __repr__() includes the type and fields that identify useful state while omitting secrets and huge collections.
def __repr__(self):
return f"Job(id={self.id!r}, status={self.status!r})"
Use a dedicated Repr instance inside the method when a field can be large.
Common mistakes
Common failures include treating repr as serialization, assuming truncation protects secrets, configuring limits too high, materializing iterators, writing a slow __repr__(), depending on set order, parsing output, and keeping snapshots that are unstable across Python versions.
Conclusion
reprlib keeps object representations readable and bounded in logs, consoles, and diagnostics. Configure a Repr instance for each context, limit depth and containers, use recursive_repr for cyclic structures, and sanitize data before formatting.
Consult the official reprlib documentation and Python ast for structural inspection tools.







