The Brotherhood of : `__str__` & `__repr__`
Tags: beginners, tutorial, python, programming
Published: 2022-03-09 13:25:08

> If you want to view the notebook version of this, you can view it [here](https://snehangsude.github.io/xSpace/python/dunder_method/oop/2022/03/03/first.html).

---

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](https://docs.python.org/3/reference/datamodel.html#special-method-names)

## 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](https://github.com/python/cpython/blob/3.10/Lib/datetime.py). 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](https://snehangsude.github.io/xSpace/python/dunder_method/oop/2022/03/03/first.html).