Python
string representation
class customization
__str__ method
duplicate

How do I change the string representation of a Python class?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Python, the string representation of an object is controlled by special methods on the class. The important part is choosing the right method for the audience: people reading logs or terminal output usually want something different from developers debugging an object in a console.

Use __str__ for Readable Output and __repr__ for Debugging

Python gives you two main hooks:

  • '__str__ for user-friendly text'
  • '__repr__ for an unambiguous developer-oriented representation'

When you call print(obj) or str(obj), Python uses __str__. When you call repr(obj) or inspect the object in many interactive environments, Python uses __repr__.

python
1class Book:
2    def __init__(self, title, author, pages):
3        self.title = title
4        self.author = author
5        self.pages = pages
6
7    def __str__(self):
8        return f"{self.title} by {self.author}"
9
10    def __repr__(self):
11        return (
12            f"Book(title={self.title!r}, "
13            f"author={self.author!r}, pages={self.pages!r})"
14        )
15
16
17book = Book("Clean Code", "Robert C. Martin", 464)
18print(str(book))
19print(repr(book))

Typical output:

text
Clean Code by Robert C. Martin
Book(title='Clean Code', author='Robert C. Martin', pages=464)

That split is a good default. The readable string is compact, while the debug representation exposes enough state to understand the object quickly.

Understand the Fallback Rules

If you do not define __str__, Python falls back to __repr__. If you define neither one, Python uses the inherited object representation, which looks like a class name plus a memory address.

python
1class Plain:
2    pass
3
4
5item = Plain()
6print(str(item))
7print(repr(item))

The output is not very helpful because it does not describe the state of the object. That is why custom classes that appear in logs, exceptions, or APIs usually benefit from at least a custom __repr__.

A practical rule is:

  • always define __repr__ for nontrivial classes
  • define __str__ when users need a cleaner display form

Keep __repr__ Informative and Safe

A strong __repr__ often looks like constructor-style output, but it does not have to be perfectly evaluable. The more important goal is clarity.

python
1class User:
2    def __init__(self, username, is_admin):
3        self.username = username
4        self.is_admin = is_admin
5
6    def __repr__(self):
7        return f"User(username={self.username!r}, is_admin={self.is_admin!r})"

The !r formatter matters because it uses each field's own repr, which adds quotes around strings and makes ambiguous values easier to distinguish.

You should also think about sensitive data. If a class contains secrets, tokens, or passwords, exclude them from __repr__ so they do not leak into logs.

Dataclasses and Formatting Hooks

If you use @dataclass, Python will generate a useful __repr__ automatically, which is often enough for small value objects.

python
1from dataclasses import dataclass
2
3
4@dataclass
5class Point:
6    x: int
7    y: int
8
9
10print(Point(3, 4))

For more specialized display logic, you can also implement __format__, which affects formatted strings such as f"{obj:short}". Most classes do not need this, but it is handy when you want multiple display modes.

python
1class Temperature:
2    def __init__(self, celsius):
3        self.celsius = celsius
4
5    def __str__(self):
6        return f"{self.celsius} C"
7
8    def __format__(self, spec):
9        if spec == "f":
10            return f"{(self.celsius * 9 / 5) + 32:.1f} F"
11        return str(self)
12
13
14t = Temperature(25)
15print(f"{t}")
16print(f"{t:f}")

Common Pitfalls

  • Putting too much text in __str__. A string representation should be concise enough for logs and debugging output.
  • Using __str__ only and skipping __repr__. Developer tools often rely on repr, so that is usually the more important method.
  • Returning non-string values. Both methods must return a string, or Python raises TypeError.
  • Exposing secrets in object output. Debug output often reaches logs, test failures, and monitoring systems.

Summary

  • Implement __str__ for readable output shown to users.
  • Implement __repr__ for detailed developer-facing output.
  • If __str__ is missing, Python falls back to __repr__.
  • Use !r inside __repr__ to make field values clearer.
  • Prefer concise, informative representations and avoid leaking sensitive state.

Course illustration
Course illustration

All Rights Reserved.