Programming
Python
Object-Oriented Programming
Class Instances
Coding Tutorial

How to print instances of a class using print()?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When you call print() on a Python object, Python asks the object for a string representation. If your class does not define one, you get the default object display, which is technically valid but rarely useful for debugging, logging, or interactive work.

What print() Actually Uses

print(obj) calls str(obj), and str(obj) looks for the object's __str__ method. If __str__ is missing, Python falls back to __repr__.

That means you usually care about two special methods:

  • '__str__ for readable output'
  • '__repr__ for developer-oriented output'

A Simple Example

Here is a class without either method:

python
1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6
7person = Person("Ava", 31)
8print(person)

The output will look like a generic instance reference, which does not tell you much about the data inside the object.

Implement __str__ for Friendly Output

If you want print() to show a human-readable summary, define __str__.

python
1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6    def __str__(self):
7        return f"{self.name} is {self.age} years old"
8
9
10person = Person("Ava", 31)
11print(person)

This is usually the right choice for CLI output, logs aimed at humans, or status messages in a small program.

Implement __repr__ for Debugging

__repr__ should be unambiguous and developer-friendly. In many codebases, it looks like valid constructor syntax.

python
1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6    def __repr__(self):
7        return f"Person(name={self.name!r}, age={self.age!r})"
8
9
10person = Person("Ava", 31)
11print(repr(person))

The !r conversion tells Python to use repr() for each field, which is helpful for strings because it keeps quotes visible.

Defining Both Methods

Many classes benefit from having both methods, each serving a different audience.

python
1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6    def __repr__(self):
7        return f"Person(name={self.name!r}, age={self.age!r})"
8
9    def __str__(self):
10        return f"{self.name} is {self.age} years old"
11
12
13person = Person("Ava", 31)
14print(person)
15print([person])

The first line uses __str__. The list display uses __repr__, because container types rely on representations that are better suited for debugging.

Dataclasses Make This Easier

If your class mostly stores data, dataclasses can generate a helpful __repr__ automatically.

python
1from dataclasses import dataclass
2
3@dataclass
4class Person:
5    name: str
6    age: int
7
8
9person = Person("Ava", 31)
10print(person)

This is a good default for data-focused classes. You can still add a custom __str__ later if you want nicer printed output.

Printing Collections of Objects

One source of confusion is that printing a list of custom objects does not call each object's __str__ method. It uses __repr__ for the elements.

python
1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6    def __repr__(self):
7        return f"Person(name={self.name!r}, age={self.age!r})"
8
9
10people = [Person("Ava", 31), Person("Ben", 28)]
11print(people)

If you only implement __str__, your objects may still look unhelpful when they appear inside a list, dict, or set.

Common Pitfalls

The most common pitfall is writing print(self) inside __str__ or __repr__. That causes infinite recursion because printing the object calls the same method again.

Another issue is making __str__ too verbose. A readable summary should be short enough to scan quickly. If you need a detailed diagnostic view, put that detail in __repr__ or a separate method.

Developers also forget that these methods must return strings. Returning a number or another object causes TypeError.

Finally, avoid putting expensive database calls, network requests, or large computations inside __str__ or __repr__. Printing an object should be cheap and predictable.

Summary

  • 'print(obj) uses __str__, and falls back to __repr__ if needed.'
  • Implement __str__ for human-readable output.
  • Implement __repr__ for debugging and container displays.
  • Use !r in f-strings to build clearer __repr__ output.
  • Consider dataclass when you want a sensible default representation with minimal code.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.