What is the difference between `__repr__` and `__str__` on a Python class?
answer
- Two audiences for one object
- One view for users, one for developers
- Only one direction has a fallback
- repr() and the REPL versus print()
- Default shows class name and address
basics
~10 s__repr__ returns the unambiguous developer-facing view, used by repr(), the REPL and debuggers. __str__ returns the readable user-facing view used by print() and str(). A missing __str__ falls back to __repr__, never the reverse.
solid answer
~40 sBoth return a string, but they serve different readers. `__repr__` is for developers: unambiguous, and ideally the expression that would rebuild the object, such as `Video(title='intro', seconds=94)`. `__str__` is for people reading output: `intro (94s)`. `repr()`, the interactive prompt, debuggers and any container printing its items call `__repr__`; `str()` and `print()` call `__str__`. The fallback runs one way only. Define no `__str__` and `str(obj)` uses `__repr__`; define no `__repr__` and `repr(obj)` gives the inherited `<module.Class object at 0x...>`, which shows identity but no state. The practical rule: write `__repr__` on every class you own, and add `__str__` only when the readable form genuinely differs from the diagnostic one.
code
python · 16 linesclass Video:
def __init__(self, title, seconds):
self.title = title
self.seconds = seconds
def __repr__(self):
return f"Video(title={self.title!r}, seconds={self.seconds!r})"
def __str__(self):
return f"{self.title} ({self.seconds}s)"
v = Video("intro", 94)
print(v) # intro (94s)
print(repr(v)) # Video(title='intro', seconds=94)
print([v]) # [Video(title='intro', seconds=94)]go deeper
Be ready to state the two audiences in one breath: __repr__ for developers, __str__ for end users, plus the fact that str() falls back to __repr__. Knowing which one print() reaches for is a routine screening check.
Explain the mechanics rather than the slogan: str() calls type(obj).__str__, whose inherited implementation delegates to __repr__, and both must return a str. Show the eval-able and angle-bracket repr conventions and when each applies.
Show the operational payoff. Reprs are what you read in logs, debuggers and failing assertions, so make writing __repr__ a reflex on every class you own, keep it one line, cheap and side-effect free, and use !r on interpolated fields.
Own it as a codebase-wide convention: a house style for what a repr includes, a rule that reprs never raise and never leak credentials, and the framing that an object's repr is part of its debuggability contract, not decoration.
Python gives an object two textual faces because two different audiences read it, and conflating them is what makes objects hard to debug. ## `__repr__` — the developer's view `repr(obj)` calls `type(obj).__repr__`. Its job is to be *unambiguous*: someone reading a log line, a debugger pane or a failing assertion should be able to tell exactly which object this is and what state it holds. The convention has two accepted shapes. - For a value-like object, return something that looks like the constructor call that would rebuild it — `Video(title='intro', seconds=94)` — so that in the simple case `eval(repr(x))` reproduces an equal object. - For an object that cannot be reconstructed from text (an open socket, a thread, a live connection), return the angle-bracket form instead: `<Extractor path='clip.mp4' frames=4800>`. The angle brackets are the standard signal for "this is a description, not an expression". Nothing in the language enforces either shape; they are conventions the whole ecosystem reads. ## `__str__` — the reader's view `str(obj)` calls `type(obj).__str__`, and `print(obj)` calls `str()` on its argument. Its job is *readability* for whoever consumes the program's output: `intro (94s)`, `3.5 MB`, `2026-09-04`. It may drop detail, round numbers, or localise. It has no obligation to be reversible. ## The one-way fallback `object.__str__` — the implementation every class inherits unless it defines its own — simply calls `__repr__`. So a class with only `__repr__` gets a sensible `str()` and prints well. The reverse does not hold: a class with only `__str__` still inherits `object.__repr__`, which produces `<__main__.Bare object at 0x1092f5e80>` — the module-qualified class name plus the memory address. That text distinguishes two instances but tells you nothing about either. This asymmetry is why the advice is always "write `__repr__` first". ## Where each one actually surfaces `__repr__` shows up in more places than beginners expect: - echoing an expression at the interactive prompt, - every element inside a printed list, tuple, set or dict, - the arguments in many library error messages, - a debugger's variables view, - and the `!r` conversion in an f-string. `__str__` shows up in `print()`, in `str()`, and — indirectly — in an f-string with no conversion and no format spec, because the inherited `object.__format__` returns `str(self)` for an empty spec. So `print(v)` and `f"{v}"` agree, while `print([v])` and `f"{v!r}"` show the repr. ## Rules that are actually enforced - Both methods must return a `str`; returning anything else raises `TypeError` at call time, not at class-definition time. - Both are looked up on the type, not on the instance. - Neither should have side effects: they are called by tooling you do not control, at moments you did not choose, sometimes many times per second while someone steps through a debugger. ## Choosing what to put in a repr - Include the class name, then the handful of fields that identify the instance — usually the ones passed to `__init__`. - Use `!r` on each field inside your f-string so that strings come out quoted and `'1'` is visibly different from `1`; that single habit removes a whole class of confusion. - Keep it to one line: a repr that wraps is unreadable in a log. - Leave out anything expensive, unbounded or secret. ## When to add `__str__` at all Only when the friendly form differs from the diagnostic form in a way that matters — a money amount rendered as `$12.50` rather than `Money(cents=1250)`, a duration as `01:34` rather than `Duration(94)`. If the two would say the same thing, one `__repr__` is enough, and you get the readable form for free through the fallback. Adding a `__str__` that merely drops the class name usually makes the object harder to debug for no gain, because it is the repr — not the str — that shows up when things go wrong. ## Two details that catch people out 1. First, the interactive prompt shows `repr()`, not `str()`: type `v` at the REPL and you get `Video(title='intro', seconds=94)`, while `print(v)` on the next line gives `intro (94s)`. The prompt renders the value of each statement through `sys.displayhook`, which uses `repr()` precisely because an interactive session is a developer context. 2. Second, a repr that hard-codes its class name lies in a subclass: if `Video.__repr__` returns the literal text `"Video(...)"`, then a `TrimmedVideo` subclass prints as a `Video` and sends the next reader looking at the wrong class. Building the name with `type(self).__name__` costs nothing and keeps the repr truthful under inheritance. Both details reinforce the same idea: the repr is a diagnostic instrument, and an instrument that misreports is worse than none.
- If a class defines only `__str__`, what does `repr(obj)` return?The inherited `object.__repr__` text: `<module.Class object at 0x7f...>`. The fallback only runs from `__str__` down to `__repr__`, so an object with a friendly `str()` can still be unreadable inside a list, in a debugger, or in a failing assertion. That is exactly why `__repr__` is the one to write first.
- What does the eval-able repr convention actually promise?It is a design goal, not a guarantee. For simple value objects, return the expression that would rebuild an equal object — `Point(x=1, y=2)` — so `eval(repr(p))` works. When the object holds live resources or cannot be reconstructed from text, the honest alternative is the angle-bracket description, `<Connection host='db1' closed>`. Nothing in the interpreter checks either form.
- Why is `!r` recommended for the fields interpolated inside a `__repr__`?Because `!r` applies `repr()` to each field, so a string field comes out quoted and nested objects show their own reprs. Without it, `Video(title=intro, seconds=94)` cannot be distinguished from a title that was the integer 94 or the string `'94'`. Quoting is what makes the repr unambiguous rather than merely informative.
__repr__ is the label a lab technician writes on the sample tube — precise, complete, meant for whoever picks it up later. __str__ is the sentence on the patient's report.
saying these in an interview costs you the question
- Claiming print() uses __repr__ when __str__ is defined
- Thinking the __str__ to __repr__ fallback works both ways
- Saying __str__ should return an eval-able expression
- Believing a class without __repr__ makes repr() fail
- Returning a non-string from __repr__ or __str__
- Defining only __str__ and expecting readable debugger output