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:
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).
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__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 context | Example | Description |
|---|---|---|
print() | print(object) | Displays the textual representation of the object |
str() | str(object) | Converts the object to a string |
| f-string | f"{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 audience | End user | Developer |
| Goal | Readability | Precision and unambiguity |
| Called by | print(), str() | repr(), interactive console |
| Fallback | Calls __repr__ if absent | Displays memory address if absent |
Here is a concrete example showing this difference:
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)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:
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:
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:
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:
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:
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 aTypeError. - 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 (Noneattributes, 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 viasuper().__str__().
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
# ❌ 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
# ❌ 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
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
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.
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.
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.
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.