How to print instances of a class using print?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
If you call print(obj) on a Python instance and see something like a memory address, Python is falling back to its default object representation. To make instances print cleanly, define __str__ for a readable display and usually __repr__ for a more precise developer-facing representation.
What print() Actually Uses
print(obj) calls str(obj), and str(obj) looks for the object's __str__ method. If __str__ is not defined, Python falls back to __repr__. If neither method is customized, you get the default inherited representation.
That means there are two useful hooks:
- '
__str__for human-friendly output' - '
__repr__for debugging and interactive inspection'
They often return related strings, but they serve different audiences.
Defining __str__
Here is the simplest useful example:
Output:
This is the method to write when you care about readable logs, command-line output, or UI-adjacent text.
Defining __repr__
__repr__ is meant for developers. A good __repr__ makes the object's state easy to inspect.
Output:
The !r conversion tells the f-string to use repr for each field, which is useful when strings, quotes, or escape sequences need to be unambiguous.
Using Both Together
In real classes, it is common to define both methods:
Typical output:
Notice the difference:
- '
print(order)uses__str__' - printing a container such as a list uses
__repr__for its elements
That is one reason __repr__ remains useful even if __str__ already looks good.
When __repr__ Alone Is Enough
For internal tools or small scripts, you may only define __repr__. Because print() falls back to __repr__, the object still prints sensibly.
This is often enough when the debugging representation is already readable.
Dataclasses Make This Easier
If your class is mainly data, dataclasses can generate a helpful __repr__ automatically.
Output:
You can still add a custom __str__ if you want a friendlier format:
What Makes a Good Representation
A strong __str__ is brief and readable. A strong __repr__ is precise enough to help debugging. If the object contains sensitive data, be selective about what you include. Printing passwords, tokens, or personal data is an avoidable mistake.
Also avoid doing expensive work in these methods. They may be called from logs, exceptions, debuggers, and interactive inspection more often than you expect.
Common Pitfalls
- Defining
__str__but forgetting__repr__, then wondering why lists or debuggers still show an unhelpful default format. - Returning something other than a string from
__str__or__repr__. Python requires both methods to returnstr. - Building representations that expose secrets such as access tokens or raw personal data. Treat object printing as part of your logging surface.
- Making
__str__do expensive database queries or other heavy work. String conversion should stay cheap and predictable. - Assuming
print(obj)uses__repr__first. It uses__str__if available and only falls back to__repr__otherwise.
Summary
- '
print(obj)uses__str__, and falls back to__repr__if needed.' - Define
__str__for human-friendly output and__repr__for debugging-oriented output. - Containers and debuggers often rely on
__repr__, so it is worth implementing well. - '
dataclassgives you a useful default__repr__with very little code.' - Keep printed representations safe, concise, and cheap to compute.

