Python `__str__()` vs `__repr__()`

Learn the difference between Python's __str__ and __repr__ magic methods, when to use each, and how to implement both for clear, debuggable objects.

6 min read

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:

pythonpython
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:

pythonpython
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

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.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between __str__ and __repr__ in Python?

The __str__ method is called by str() and print() and should return a human-readable description of the object suitable for end users. The __repr__ method is called by repr() and is shown in interactive Python sessions; it should return an unambiguous description, ideally one that could recreate the object. If you only implement one, implement __repr__, because Python falls back to __repr__ when __str__ is not defined, but the reverse is not true.

Why does print() sometimes show the same output as repr()?

When a class does not define __str__, Python falls back to __repr__ for all string conversion needs. The print function, the str built-in, and f-string interpolation all use __str__ when it exists and __repr__ as a fallback. This is why the default string representation of objects you see in print output looks like the repr output: your class inherits a default __repr__ from the object base class and has no __str__ to override it.

Should I always implement both __str__ and __repr__?

For most classes, implementing __repr__ is sufficient and implementing both is ideal. __repr__ ensures your objects display useful information in debuggers, log files, and interactive sessions. Add __str__ when your class has a natural human-readable format that differs from the developer-focused repr output. For simple data classes, the two representations are often identical, and implementing both with the same logic is acceptable.

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.