What is a repr in Python?
In Python, the term repr refers to the string representation of an object that is intended to be unambiguous and, ideally, useful for debugging or recreation. When you call the built‑in repr() function on an object, Python looks for the object’s __repr__ method and returns the string it produces. This representation is often used in interactive shells, logging, and test assertions because it aims to show the “official” form of an object—one that, if possible, could be used to recreate the object with eval().
Understanding the __repr__ Method
Every Python class can define a special method named __repr__. This method takes no arguments besides self and must return a string. The interpreter invokes __repr__ in several contexts:
- When you type an object’s name in the REPL and press Enter.
- When you call
repr(obj)explicitly. - When an object is placed inside a container (like a list or dict) and the container’s own
__repr__needs to display its elements.
If a class does not define __repr__, Python falls back to the default implementation from the object base class, which returns a string of the form <module.ClassName object at 0x...>. While this tells you the object's type and memory address, it provides little insight into the object's data Turns out it matters..
You'll probably want to bookmark this section.
Why __repr__ Matters
- Debugging clarity – A well‑crafted
__repr__lets developers see the essential state of an object at a glance, speeding up troubleshooting. - Reproducibility – When the string resembles a valid Python expression that could recreate the object (e.g.,
MyClass(42, 'hello')), you can copy‑paste it into a shell or test to get an identical instance. - Consistent logging – Many logging frameworks call
repr()on objects to produce readable log entries without requiring custom formatters. - Container representation – Lists, tuples, sets, and dictionaries rely on the
__repr__of their elements to show their contents. If elements have poor__repr__, the container’s output becomes noisy or misleading.
__repr vs __str__
Python provides two string‑related special methods:
| Method | Purpose | Typical Use |
|---|---|---|
__repr__ |
“Official” representation; unambiguous, often evaluable. | Debugging, development, logging. |
__str__ |
“Informal” representation; readable for end users. | Displaying information to users, UI, reports. |
If __str__ is not defined, Python defaults to __repr__. Plus, conversely, if __repr__ is missing, Python uses the generic <... > form. A good practice is to implement __repr__ first, ensuring it is unambiguous, and then optionally provide a __str__ that offers a friendlier format.
How to Implement __repr__
A typical __repr__ follows this pattern:
def __repr__(self):
return f"{self.__class__.__name__}({self.attribute!r}, {self.other_attribute!r})"
Key points:
- Use
!r(thereprconversion specifier) inside f‑strings to ensure each attribute is represented with its own__repr__. - Include the class name so the output clearly identifies the type.
- Aim for a string that, when passed to
eval(), would recreate an equivalent object (if the constructor accepts those arguments). - Keep the representation concise but informative; avoid dumping huge data structures unless necessary.
Example: A Simple Point Class
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x!r}, {self.y!r})"
def __str__(self):
return f"({self.x}, {self.y})"
Interaction:
>>> p = Point(3, 4)
>>> repr(p)
'Point(3, 4)'
>>> str(p)
'(3, 4)'
>>> eval(repr(p)) == p # True if __eq__ is defined appropriately
True
Here, repr(p) returns a string that looks like a constructor call, making it easy to rebuild the point.
Best Practices for __repr__
- Be unambiguous – Two distinct objects should ideally produce different
__repr__strings. - Prefer evaluable output – If the object’s constructor can take the shown arguments, mimic that call.
- Avoid side effects –
__repr__should not modify the object or perform expensive computations. - Keep it short – Long representations clutter logs and consoles; summarize large attributes (e.g., show length of a list instead of all items).
- Document the format – If the representation follows a convention (like
<ClassName attr=value>), mention it in the class docstring so users know what to expect. - Test it – Include unit checks that verify
eval(repr(obj))yields an equivalent object when possible.
Common Pitfalls
- Returning non‑string types –
__repr__must return astr; returning anything else raises aTypeError. - Infinite recursion – If
__repr__callsrepr()on an attribute that, in turn, calls__repr__on the original object, you get aRecursionError. Guard against this by checking for self‑references or usingrepr()on built‑in types only. - Exposing sensitive data – Including passwords, tokens, or personal data in
__repr__can leak information via logs or debug consoles. Consider masking or omitting such fields. - Over‑loading with too much detail – Dumping massive nested structures makes the output unusable; instead, show a summary or a hash.
Frequently Asked Questions
Q: Do I need to define both __repr__ and __str__?
A: Not required. If you only define __repr__, Python will use it for both repr() and str() calls. Define __str__ only when you want a distinct, user‑friendly format And that's really what it comes down to..
Q: Can __repr__ return a multiline string?
A: Technically yes, but most tools (like the interactive shell) display it on a single line. Multiline representations can confuse readers and break expectations of containers that rely on __repr__ for element display.
Q: What if my object’s constructor takes many arguments?
A: You can still mimic the call, but consider using keyword arguments for clarity: MyClass(a=1, b=2, c=3). If the argument list is excessively long, a summary like MyClass(<10 items>) may be more practical.
**Q: Is