Python's two string representation methods serve different audiences and appear in different contexts, and understanding the distinction between them is essential for writing classes that behave predictably when printed, logged, debugged, or inspected in an interactive session. The str method, called by the built-in str function and by print, provides a human-readable description of an object. Its output is meant for end users who care about what the object represents, not how it was constructed. The repr method, called by the built-in repr function and by the interactive Python interpreter, provides an unambiguous description of an object intended for developers. Its output should, ideally, look like valid Python code that could be used to recreate the object. The two methods answer different questions: str answers "what is this?" and repr answers "how was this made?"
Every Python object inherits a default repr implementation from the base object class, which produces output like <main.MyClass object at 0x7f8b1c0a3d90>. This default is rarely useful for debugging because it tells you the class name and memory address but nothing about the object's actual state. Implementing a custom repr on your classes is one of the highest-value improvements you can make to your development workflow, because every debugger, every log message, and every interactive session will show meaningful information instead of opaque memory addresses. The article on common magic methods in Python covered the broader magic method landscape. This article focuses specifically on the two string representation methods because they are among the most frequently implemented and most frequently confused magic methods in the language.
The distinction between str and repr is not just about different output formats. It is about different audiences and different guarantees. The repr output should be unambiguous: given the repr output alone, a developer should be able to identify exactly which object is being described. The str output should be readable: given the str output, a user should understand what the object represents without needing to know about the class's internal structure. For simple value objects like points and dates, the two representations are often identical because the human-readable form and the constructor form happen to look the same. For more complex objects, the representations diverge.
Implementing repr for debuggable objects
The repr method should return a string that is useful to a developer who is debugging code or inspecting objects in an interactive session. The gold standard for repr output is that it should look like a valid Python expression that, when evaluated, would recreate an object with the same state. This standard is aspirational rather than absolute; for objects that depend on external resources like database connections or file handles, an exact reconstruction string is not possible. In those cases, the repr should include the class name and the key attributes that identify the object.
Here is a class that implements repr according to the gold standard, returning a string that could be pasted back into Python to create an equivalent object:
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __repr__(self):
return f"Book({self.title!r}, {self.author!r}, {self.pages!r})"The repr uses the !r format specifier inside the f-string, which calls repr on each argument rather than str. This ensures that strings are quoted and special characters are escaped, so the output is a syntactically valid Python expression. For a Book instance with the title "Dune", the repr output is Book('Dune', 'Frank Herbert', 412), which is exactly the code you would write to create that object.
The benefit of a good repr becomes apparent the first time you debug a list of objects. Printing a list calls repr on each element, not str. If your repr shows constructor-style output, the list display tells you exactly what objects are in the list. If your repr shows the default memory address output, the list display is a wall of angle brackets that tells you nothing. Investing two minutes in writing a repr method saves hours of debugging over the lifetime of a class.
Implementing str for user-friendly display
The str method should return a string that a non-developer would find meaningful. It is called by print, by str, and by f-string interpolation when the object appears in an f-string without a format specifier. The str output should omit implementation details and focus on what the object represents in the problem domain.
Here is the Book class with both methods, where str provides a formatted bibliographic entry and repr provides the constructor form:
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f"'{self.title}' by {self.author} ({self.pages} pages)"
def __repr__(self):
return f"Book({self.title!r}, {self.author!r}, {self.pages!r})"When you print a Book object, the user sees 'Dune' by Frank Herbert (412 pages), which reads like a library catalog entry. When you inspect a Book in an interactive session or print a list of Books, the developer sees Book('Dune', 'Frank Herbert', 412), which shows the exact constructor arguments. Both representations serve their respective audiences, and neither is redundant with the other.
The distinction also matters for container types. When you print a list, Python calls repr on each element, not str. This means a list of Books displayed in an interactive session shows the constructor-style repr output for each Book. When you iterate over the list and print each Book individually, you see the human-readable str output. The choice of which representation appears where is handled automatically by Python based on the context, and implementing both methods gives you the right output in every context.
Practical guidelines for both methods
The most important guideline is to always implement repr, because Python provides no useful default. A minimal repr that includes the class name and the values of the most important attributes is infinitely better than the default memory address output. The str method is optional but recommended when there is a natural human-readable format that differs from the developer-focused repr output.
For simple data classes where the constructor arguments fully describe the object, the two representations can be identical. Implementing repr to return the constructor form and letting str fall back to it is a valid pattern. For classes that represent values with a natural display format, like currency amounts, dates, or measurements, str should return the formatted display value and repr should return the constructor form. A Money class might have str return "$42.00" and repr return "Money(42, 'USD')".
The article on operator overloading with Python magic methods covers additional magic methods for arithmetic and comparison, and the string representation methods covered here are the natural starting point for any class's magic method implementation. Start with repr, add str when the human-readable form differs, and both your users and your fellow developers will thank you.
Rune AI
Key Insights
- str provides a human-readable string for end users, called by print() and str().
- repr provides an unambiguous string for developers, called by repr() and shown in interactive sessions.
- Python falls back to repr when str is not defined, so always implement repr at minimum.
- A good repr returns a string that looks like valid Python code to recreate the object.
- The two representations are often different; str might show a formatted name while repr shows the constructor call.
Frequently Asked Questions
What is the difference between __str__ and __repr__ in Python?
Why does print() sometimes show the same output as repr()?
Should I always implement both __str__ and __repr__?
Conclusion
The str and repr methods control how your objects appear as strings in different contexts. repr is for developers: it should be unambiguous and useful for debugging. str is for users: it should be readable and appropriate for display. Implementing at least repr on every class you write is a small investment that pays off every time you debug, log, or inspect your objects.
More in this topic
Create Custom Iterators in Python
Learn how to build your own iterators in Python by implementing the __iter__() and __next__() methods, with practical examples and reusable patterns.
Python Iterator Protocol Explained
Learn how Python's iterator protocol works with the __iter__() and __next__() methods, and understand the contract every iterator must follow.
Python Iterables and Iterators Explained
Learn what iterables and iterators are in Python, how they power for loops under the hood, and why understanding them unlocks cleaner data processing patterns.