Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

What is __repr__ in Python

Understanding __repr__ in Python

When you’re learning to program in Python, you’ll encounter many special methods that are surrounded by double underscores. These are often referred to as “magic” methods due to their automatic triggering during various aspects of an object’s lifecycle. One such method is __repr__, which stands for “representation”. But what exactly does it do, and why is it important for your Python objects?

The Purpose of __repr__

Imagine you have a book in your hand. You can describe it in many ways: by its cover, by its content, or perhaps by summarizing its plot. Similarly, objects in Python can be represented in different ways for human understanding. The __repr__ method is like the summary on the back cover of the book. It's meant to give a clear and unambiguous description of the object.

The primary goal of __repr__ is to be unambiguous and, if possible, to be a string that looks like a valid Python expression that could be used to recreate the object. In other words, __repr__ is a way for you to tell Python how to print objects of a class in a way that’s informative and as close as possible to how the object was created.

A Simple Example

Let's start with a simple example to see __repr__ in action. Suppose you have a class Point that represents a point in a two-dimensional space:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)
print(p)

If you run this code, the output might look something like this:

<__main__.Point object at 0x000002B2D8F8A0A0>

This is Python's default way of showing that p is an object of the Point class located at a specific memory address. Not very informative, right? This is where __repr__ comes in.

Implementing __repr__

To make the representation of the point more informative, you can define the __repr__ method in the Point class:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f'Point({self.x}, {self.y})'

p = Point(1, 2)
print(p)

Now, when you print the object p, you get a much more informative output:

Point(1, 2)

This output tells you that p is an object of the Point class and it was created with the values 1 and 2 for x and y, respectively.

When is __repr__ Called?

The __repr__ method is called by the repr() built-in function. It is also used by the print() function when you try to print an object, and there is no __str__ method defined. The __str__ method is another special method that's supposed to return a readable, informal representation of an object, which is more for end-user consumption.

Intuitions and Analogies

To understand __repr__, let’s use an analogy. Imagine you’re an artist, and you’ve created a sculpture. If someone asked you to describe your sculpture in a single sentence that could be used to recreate it, you would try to be as precise and detailed as possible. That’s what __repr__ does—it’s the precise and detailed description of an object that, in the best-case scenario, can be used to recreate it.

Best Practices for __repr__

When implementing __repr__, it’s important to adhere to some best practices:

  1. Make it unambiguous: The output should clearly identify that the string is a description of an object of a specific class.
  2. Try to make it useful for recreating the object: If possible, the string should look like a valid Python expression that could be used to recreate the object with the same state.
  3. Keep it concise: While it should be detailed, it should also be concise enough to be readable.

A More Complex Example

Let's consider a more complex class, Rectangle, which represents a rectangle using the coordinates of its bottom-left and top-right corners:

class Rectangle:
    def __init__(self, bottom_left, top_right):
        self.bottom_left = bottom_left
        self.top_right = top_right

    def __repr__(self):
        return (f'Rectangle({self.bottom_left.__repr__()}, '
                f'{self.top_right.__repr__()})')

bottom_left = Point(0, 0)
top_right = Point(5, 10)
rectangle = Rectangle(bottom_left, top_right)
print(rectangle)

The output will be:

Rectangle(Point(0, 0), Point(5, 10))

This representation is clear and could potentially be used to recreate the Rectangle object with the same state.

Conclusion: The Magic of __repr__

In the world of Python programming, understanding the magic methods can feel like learning the secrets of a great magician. The __repr__ method is one such enchanting spell that allows programmers to define how objects should be presented in the realm of code. By using __repr__, you can ensure that the essence of your objects is captured in a string format that is not only informative but also capable of bringing the object back to life if needed.

As you continue on your programming journey, remember that the power of __repr__ is like giving your objects a voice. With it, they can tell the story of their creation and identity, making your debugging sessions less of a mystery and more of a narrative to follow. So, go forth and give your objects the ability to speak for themselves, and watch as your code becomes a well-documented tale of logic and functionality.