The Brotherhood of : `__str__` & `__repr__`

The Brotherhood of : `__str__` & `__repr__`

Understanding the difference between `__str__` and `__repr__`. How they help with debugging and the way to reproduce them in your own code.

If you want to view the notebook version of this, you can view it here.

Diving in the nitty-gritty details of Python introduces us to Dunder Methods. Dunder means "double underscores" as it starts and ends with two underscores. A dunder method acts as a contract between the Python interpreter and the person who made a particular Python class.

For example, the len method, it helps us with the length of any given string or list or a dictionary, however, it uses a dunder method __len__. Since the length of something is fundamental to any programming language it was made a built-in method but nonetheless, it internally delegates the task to __len__.

>>> integers = [1, 2, 3, 4, 5]
>>> len(integers)
Output: 5

>>> integers.__len__()
Output: 5

There are quite a few built-in functions that internally use dunder methods to work, such as indexing which uses __getitem__, or print which uses __str__. If you are interested to know about all dunder methods here's a good resource: Dunder Methods

The Difference

Understanding __str__ & __repr__ allows us greater control for us to not only edit and upgrade classes but also to debug and create libraries. In a nutshell, if I had to explain to you about __str__ or __repr__ they both do the same thing i.e. they print an output. However, __repr__ is mostly used by programmers to debug, and __str__ is for the users using the program. Let's dive in to see how exactly are they both different and learn about when to use which!

>>> repr('Triceratops')
Output: "'Triceratops'"

>>> str('Triceratops')
Output: 'Triceratops'

Looking at the above lines of code, there isn't much difference apart from the fact that repr('Triceratops') throws us an output which is within a double-inverted comma ("") and then the string within a single-inverted ('') comma. As for the str('Triceratops') it's within a single-inverted comma(''). If you ask me, that's not even a difference as both of them do the same exact thing and there isn't much difference.

Let's look at something a bit more interesting.

>>> import datetime

>>> current_time = datetime.datetime.now()
>>> print(current_time)
Output: 2022-03-03 01:04:19.955451

>>> str(current_time)
Output: 2022-03-03 01:04:19.955451

>>> repr(current_time)
Output: 'datetime.datetime(2022, 3, 3, 1, 4, 19, 955451)'

Fascinating, isn't it!

While using the datetime library we created a variable current_time which stores as the variable says, the current time. Running a print statement gives us an output that is similar to the output when we use the current_time variable inside the str() function. A user-friendly output of the variable giving is the year-month-date hour:minutes:seconds.

However, using the same variable inside the repr() function gives us an entirely different output. It tells us that it's a datetime object which holds the values (year, month, day, hour, minutes, seconds, microseconds). A developer-friendly output that provides adequate information for a developer to understand.

The Brotherhood

While it may be intriguing to prefer one over another, truth be told, we need both of them to make sure they cover both cases. The general idea is to make the __repr__ function help you as much as you can with maximum details. While the __str__ function with the minimum details which a user can read or understand. For example:

Defining a class:

>>> class Dinosaur:
    ... def __init__(self, name):
        ... self.name = name

>>> def __repr__(self):
    ... return (f'{self.name.__class__.__name__}({self.name})')    

>>> def __str__(self):
        ... return (f'{self.name}')

Code:

>>> dino = Dinosaur(1)
>>> print(dino)
Output: 1

>>> str(dino)
Output: 1

>>> repr(dino)
Output: int(1)

Note: __class__ and __name__ represents the name of the class the name belongs to.

Conclusion

Now that, you have got a grasp into what __repr__ & __str__ does, you are one step closer to debugging your own code. Try creating a class that gives you all the information using repr() but only the necessary one using str().

If you are interested to know about how datetime wrote their library __repr__ and __str__ function, you can see the source code here. It might be overwhelming when you look at the code but try to search through the document to find __str__ and __repr__. Hint: Use Ctrl + F. This will give you a broader idea of how these functions are different, yet so similar.

Oh! And something interesting while I was working on this article, I saw the Jupyter notebooks use __repr__ when the output is requested without the print. If you want to view the notebook version of this you can use view it here.