What is __str__ in Python?

Discover the __str__ special method in Python: definition, practical examples, difference with __repr__, and best practices for representing your objects.
8 min read
Believemy logo

Definition of __str__ in Python

The __str__ method is a special method (also called a dunder method or magic method) in Python that allows you to define the string representation of an object. When you use the print function on an object or call str(), Python automatically invokes the __str__ method of that object to obtain a readable, human-friendly representation.

In other words, __str__ allows you to control what is displayed when a user asks to see your object as text. It is a fundamental concept of object-oriented programming in Python, which you can explore in depth through our comprehensive Python course.

Concretely, without __str__, displaying a custom object looks like this:

PYTHON
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

u = User("Alice", 30)
print(u)
# Result: <__main__.User object at 0x7f8b8c0d4a90>

This result is not very helpful. Thanks to __str__, you can transform this display into something much more useful and readable.

 

Syntax and behavior of __str__

The __str__ method is defined inside a Python class. It takes only self as a parameter and must always return a string (str).

PYTHON
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"{self.name}, {self.age} years old"

u = User("Alice", 30)
print(u)
# Result: Alice, 30 years old
Good to know

__str__ must always return an object of type str. If you return another type (an integer, a list, etc.), Python will raise a TypeError.

Here are the situations in which Python automatically calls __str__:

Call contextExampleDescription
print()print(object)Displays the textual representation of the object
str()str(object)Converts the object to a string
f-stringf"{object}"Inserts the representation into an f-string
format()"{}".format(object)Used in string formatting

 

Difference between __str__ and __repr__

One of the most common questions in Python concerns the difference between __str__ and __repr__. Both methods serve to represent an object as text, but they have fundamentally different goals.

Criterion__str____repr__
Target audienceEnd userDeveloper
GoalReadabilityPrecision and unambiguity
Called byprint(), str()repr(), interactive console
FallbackCalls __repr__ if absentDisplays memory address if absent

Here is a concrete example showing this difference:

PYTHON
class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __str__(self):
        return f"{self.name} — ${self.price}"

    def __repr__(self):
        return f"Product(name='{self.name}', price={self.price})"

p = Product("Mechanical Keyboard", 89.99)

print(str(p))   # Mechanical Keyboard — $89.99
print(repr(p))  # Product(name='Mechanical Keyboard', price=89.99)
Warning

If you only define __repr__ without __str__, Python will use __repr__ as a fallback when __str__ is called. The reverse is not true: if only __str__ is defined, repr() will not use __str__.

As a general rule, we recommend always defining __repr__ first (for debugging) and adding __str__ when you want a more user-friendly display for the end user.

 

Practical examples

Representing a simple object

Let's start with a basic example using a class representing a book:

PYTHON
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)"

book = Book("The Little Prince", "Saint-Exupéry", 96)
print(book)
# 'The Little Prince' by Saint-Exupéry (96 pages)

 

Using __str__ in a collection of objects

When you place objects in a list or a dict, the behavior differs. Inside a collection, Python uses __repr__ and not __str__. Here is how to handle this:

PYTHON
class Student:
    def __init__(self, name, average):
        self.name = name
        self.average = average

    def __str__(self):
        return f"{self.name} (average: {self.average}/20)"

    def __repr__(self):
        return self.__str__()

students = [
    Student("Alice", 15.5),
    Student("Bob", 12.0),
    Student("Charlie", 17.8)
]

# Individual display → uses __str__
for s in students:
    print(s)
# Alice (average: 15.5/20)
# Bob (average: 12.0/20)
# Charlie (average: 17.8/20)

# List display → uses __repr__
print(students)
# [Alice (average: 15.5/20), Bob (average: 12.0/20), Charlie (average: 17.8/20)]

 

__str__ with class inheritance

The __str__ method can be inherited and overridden in child classes. This is a powerful mechanism of polymorphism in Python:

PYTHON
class Animal:
    def __init__(self, name, species):
        self.name = name
        self.species = species

    def __str__(self):
        return f"{self.name} is a {self.species}"

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name, "dog")
        self.breed = breed

    def __str__(self):
        return f"{super().__str__()} of breed {self.breed}"

class Cat(Animal):
    def __init__(self, name, indoor=True):
        super().__init__(name, "cat")
        self.indoor = indoor

    # No __str__ defined → uses the parent's

rex = Dog("Rex", "German Shepherd")
whiskers = Cat("Whiskers")

print(rex)      # Rex is a dog of breed German Shepherd
print(whiskers) # Whiskers is a cat

 

__str__ with dataclasses

dataclass automatically generate a __repr__ method, but not a custom __str__. If you want a different display from the default, you must define it manually:

PYTHON
from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float

    def __str__(self):
        return f"Point({self.x}, {self.y})"

p = Point(3.5, 7.2)
print(p)       # Point(3.5, 7.2)
print(repr(p)) # Point(x=3.5, y=7.2)  ← automatically generated

 

Advanced example: multi-line formatted display

Nothing prevents you from returning a multi-line string in __str__. This is particularly useful for complex objects:

PYTHON
class Invoice:
    def __init__(self, number, client, lines):
        self.number = number
        self.client = client
        self.lines = lines  # list of tuples (description, amount)

    def total(self):
        return sum(amount for _, amount in self.lines)

    def __str__(self):
        header = f"Invoice #{self.number} — Client: {self.client}"
        separator = "-" * 45
        lines_text = "\n".join(
            f"  {desc:<30} ${amount:>8.2f}"
            for desc, amount in self.lines
        )
        total_text = f"  {'TOTAL':<30} ${self.total():>8.2f}"
        return f"{header}\n{separator}\n{lines_text}\n{separator}\n{total_text}"

invoice = Invoice("2024-001", "Believemy", [
    ("Python Course", 299.00),
    ("Premium Support", 49.99),
    ("Certificate", 19.99)
])

print(invoice)
# Invoice #2024-001 — Client: Believemy
# ---------------------------------------------
#   Python Course                      $299.00
#   Premium Support                     $49.99
#   Certificate                         $19.99
# ---------------------------------------------
#   TOTAL                              $368.98

 

Best practices

Here are the essential rules to follow when implementing __str__ in your Python classes:

  • Always return a str: This is mandatory. Any other type will cause a TypeError.
  • Keep the message concise and readable: __str__ is intended for the end user, not the developer. Avoid unnecessary technical details.
  • Also define __repr__: Don't rely solely on __str__. Always implement __repr__ for debugging.
  • Avoid side effects: The __str__ method should never modify the state of the object. It should be a read-only operation.
  • Use f-string: They are the most readable and performant way to build the return string.
  • Don't raise exceptions: __str__ should always succeed. Handle edge cases (None attributes, empty lists, etc.) with default values.
  • Think about inheritance: If your class is meant to be inherited, design __str__ so that it can be extended via super().__str__().
Good to know

A good rule to remember: __str__ answers the question "How should I present this object to a user?" while __repr__ answers "How can I recreate this object?".

 

Common mistakes to avoid

Here are the most frequent pitfalls encountered by Python developers when working with __str__:

1. Forgetting to return a string

PYTHON
# ❌ Bad: print instead of return
class Bad:
    def __str__(self):
        print("My object")  # Returns nothing (None)

# ✅ Good: return the string
class Good:
    def __str__(self):
        return "My object"

 

2. Returning an incorrect type

PYTHON
# ❌ Bad: returns an integer
class Counter:
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return self.value  # TypeError if value is not str!

# ✅ Good: convert to string
class Counter:
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return str(self.value)

 

3. Confusing __str__ and __repr__ in collections

PYTHON
class Element:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

    # __repr__ not defined!

elements = [Element("A"), Element("B"), Element("C")]
print(elements)
# [<__main__.Element object at 0x...>, ...]
# __str__ is NOT used in lists!

 

Frequently asked questions

Question

What is the difference between __str__ and __repr__ in Python?

__str__ is designed to produce a representation that is readable for the end user, while __repr__ aims for an unambiguous representation for the developer, ideally capable of recreating the object. When you call print or str(), __str__ is invoked. In the interactive console or via repr(), it is __repr__. If __str__ is not defined, Python uses __repr__ as a fallback.

 

Question

Should you always define __str__ in your Python classes?

It is not mandatory, but it is strongly recommended whenever your objects are likely to be displayed. At a minimum, you should always define __repr__ to facilitate debugging. Add __str__ when you need a user-friendly display that differs from the technical representation. For dataclass, __repr__ is automatically generated, which is often sufficient.

 

Question

Can you use __str__ with Python's built-in types?

Yes, all of Python's built-in types (int, float, list, dict, tuple, etc.) already have an implementation of __str__. This is precisely why print([1, 2, 3]) displays [1, 2, 3] instead of the memory address of the list object. You cannot modify __str__ on built-in types directly, but you can create subclasses if needed.

 

Question

How can I learn to master __str__ and Python special methods?

Special methods like __str__, __repr__, __init__, __eq__, or __len__ (related to len) are at the heart of object-oriented programming in Python. To master them fully, we recommend following our dedicated Python course on Believemy, which covers in detail class creation, special methods, and Python development best practices.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.