Classes in Python has a number of built-in features that you can customize. These features are accessible through methods defined by Python itself. Often, these methods are surrounded by two underscores, or a double underscore. Thus such a method is sometimes referred to as a “dunder method”.
Two of these “dunder methods”, __str__
and __repr__
let you customize the string representations of an object. In this post, you’ll see how to override the __str__
and __repr__
methods and more about their use cases. But first, we’ll need a class.
class TodoItem:
def __init__(self, task, priority=0, complete=False):
self.task = task
self.priority = priority
self.complete = complete
def set_complete(self):
self.complete = True
Now let’s create an instance of the TodoItem class (an object) and print it to the console.
if __name__ == "__main__":
my_next_task = TodoItem("My next task")
print(my_next_task)
Here is the result on my machine:
<__main__.TodoItem object at 0x7f02a442d1d0>
Not very useful. This simply say that my_next_task
is an object of type TodoItem
in the __main__
module at this memory address. Again the memory address on your machine will be different.
To make this a little more useful, let’s override the __repr__ (pronounced “dunder repper”) method to return the values of the attribute of the object.
class TodoItem:
# existing code
def __repr__(self):
is_complete = "not complete" if not self.complete else "complete"
return f"<TodoItem task='{self.task}', priority={self.priority}, {is_complete}>"
Run the app again and you’ll see this:
<TodoItem task='My next task', priority=0, not complete>
This is indeed more useful. It appears when you display the value of an object with the print
function, behind the scenes, Python calls the __repr__
method of the object and displays the return value.
But what does the __str__ method do? Let’s add one and find out.
class TodoItem:
# existing code
def __str__(self):
is_complete = "not complete" if not self.complete else "complete"
return f"TodoItem(task='{self.task}', priority={self.priority}, {is_complete})"
Now run the app again.
TodoItem(task='My next task', priority=0, not complete)
Now it looks like when using the print
function, the default behavior is to call the __str__
method, and output the return value to the console. But if there is not __str__
method override, use the __repr__
method. And if there is no __repr__
method, use the default representation with the type and memory location.
So what is the intended use of the __repr__
method other than a fallback when there is no __str__
override? To answer that question, we’ll need to open an interactive prompt or REPL such as IPython. At the prompt, import the TodoItem
class. Create a new instance. Then get the value, but don’t use the print
function.
Now we can see the intended use of the __repr__
function. It’s the default for getting the string representation of an object in the REPL. However, you can still use the print function and get the __str__
representation as well:
The __str__
representation will also be used if you call the str
initializer.
In this example, we used string representations that were just different enough to tell which function they came from. But in the real world, what data should each one display?
If you think about it, you’re not going to have that many end users inspecting your code through an interactive REPL. Therefore, this is a use case for more technical users who are going to be looking for more technical information. And that is what should be displayed by the __repr__
method. But end users are going to want to see a more friendly string representation and in that case the __str__
method should be used.
Summary
In this post you saw the difference between the __str__
and __repr__
methods. The __str__
method is called when getting the string representation of an object via the print function or str initializer. It is intended to be friendly and consumed by end users. Technical users will be using tools like an interactive REPL and expect technical details in the string representation. This is when Python defaults to the __repr__
method string representation. There is also a default Python string representation that displays the type of the object and it’s memory address.