What is the difference between `__repr__` and `__str__`, and when is each called?
__repr__ and __str__ both produce string representations, but they serve different audiences:
__repr__: Developer-facing. Should be unambiguous and ideally return a string that could recreate the object (eval(repr(obj)) == obj). Called by repr(), the interactive interpreter, and when objects are displayed inside containers (lists, dicts).
__str__: User-facing. Should be readable and informative. Called by str(), print(), and f-strings.
Fallback behavior: If __str__ is not defined, Python uses __repr__ as the fallback. The reverse is NOT true -- missing __repr__ falls back to the default object.__repr__ (e.g., <MyClass object at 0x...>).
Priority rule: Always implement __repr__. Only add __str__ if you need a different user-facing representation.
1. repr(obj) -> obj.__repr__()
2. str(obj), print(obj), f'{obj}' -> obj.__str__()
3. If __str__ missing -> falls back to __repr__
4. Containers (list, dict) always use __repr__ for elements
5. Interactive console uses __repr__
from datetime import datetime
class Transaction:
def __init__(self, amount, currency, timestamp=None):
self.amount = amount
self.currency = currency
self.timestamp = timestamp or datetime.now()
def __repr__(self):
return (f"Transaction({self.amount!r}, {self.currency!r}, "
f"timestamp={self.timestamp!r})")
def __str__(self):
return f"{self.currency} {self.amount:,.2f}"
t = Transaction(1234.5, "USD")
# __repr__ -- for developers
print(repr(t)) # Transaction(1234.5, 'USD', timestamp=datetime.datetime(...))
# __str__ -- for users
print(str(t)) # USD 1,234.50
print(t) # USD 1,234.50 (print uses __str__)
print(f"Payment: {t}") # Payment: USD 1,234.50 (f-string uses __str__)
print(f"Debug: {t!r}") # Debug: Transaction(...) (f-string with !r uses __repr__)
# Containers ALWAYS use __repr__
transactions = [Transaction(100, "USD"), Transaction(200, "EUR")]
print(transactions) # [Transaction(100, 'USD', ...), Transaction(200, 'EUR', ...)]
# Without __str__, __repr__ is used everywhere
class OnlyRepr:
def __repr__(self):
return "OnlyRepr()"
obj = OnlyRepr()
print(str(obj)) # OnlyRepr() -- falls back to __repr__
print(repr(obj)) # OnlyRepr()
# Use !r in __repr__ to quote strings properly
class User:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"User({self.name!r})" # !r adds quotes: User('Alice')
print(repr(User("Alice"))) # User('Alice')
- •__repr__ for developers (unambiguous), __str__ for users (readable)
- •Containers use __repr__ for elements, not __str__
- •__str__ falls back to __repr__ if not defined
- •Use !r in f-strings to force __repr__
- •print([obj]) uses __repr__, not __str__ -- surprising for beginners
- •If you only implement __str__, debugging output shows unhelpful <object at 0x...>
- •eval(repr(obj)) == obj is an ideal, not always achievable