The Python Magic Methods: __str__ vs __repr__

Introduction

Python, being a high-level, interpreted language, is known for its easy readability with great design principles. However, when you delve deeper into Python, some things may seem complex if you're coming from a language that doesn't have a similar feature. One such feature is the concept of magic methods, and in this Byte, we're going to demystify what __str__ and __repr__ magic methods are, their differences, and why and when to use each.

What are Magic Methods?

Magic methods in Python are special methods that add "magic" to your classes. They're always surrounded by double underscores (e.g. __init__ or __lt__). These methods are also known as dunder methods, short for "double under." Magic methods are not meant to be invoked directly by you, but the invocation happens internally from the class on a certain action. For instance, when you add two numbers using the + operator, internally, the __add__ method will be called.

class Number:
    def __init__(self, num):
        self.num = num

    def __add__(self, other):
        return self.num + other.num

num1 = Number(2)
num2 = Number(3)

print(num1 + num2)  # Output: 5

In the example above, you can see that the __add__ method is being used to enable the use of the + operator. This is the magic of magic methods!

Magic methods can make your classes act more like Python built-in types, and make your code more intuitive and cleaner.

Understanding __str__ Method

The __str__ method in Python represents the "informal" or nicely printable string representation of an object. This method is called by the str() built-in function and by the print function to convert the object into a string.

Let's take a look at an example where we define a Person class with a __str__ method:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'Person(name={self.name}, age={self.age})'

p = Person('John Doe', 30)
print(p)

The output of this code would be:

Person(name=John Doe, age=30)

In this example, the __str__ method returns a string that represents the Person object in a human-readable form.

Understanding __repr__ Method

On the other hand, the __repr__ method returns a string that describes a precise, unambiguous representation of an object. The main goal of this method is to be explicit about the object's information. It's meant to be used in debugging and development. The __repr__ method is called by the repr() built-in function.

Here's an example where we define a Person class with a __repr__ method:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f'Person(name={self.name!r}, age={self.age!r})'

p = Person('John Doe', 30)
print(repr(p))

The output of this code would be:

Person(name='John Doe', age=30)

In this example, the __repr__ method returns a string that if evaluated, would produce an object equivalent to p. Notice the use of !r in the format string to ensure the output string uses repr() instead of str(). This is part of the attempt to make the output unambiguous.

Note: If you don't define a __str__ method in your class, Python will call the __repr__ method when attempting to print an object.

Differences Between __str__ and __repr__

In Python, __str__ and __repr__ are two magic methods that serve different purposes. At first glance, they might seem similar as they both return a string representation of the object. However, the key difference between them lies in their intended audience and the level of detail they provide.

The __str__ method is meant to provide a concise, human-readable description of an object. It's what you’ll see when you print an object. On the other hand, __repr__ is intended to provide a complete and unambiguous representation of the object, which is more useful for developers. It's what you’ll see when you display the object in the console.

Here's an example to illustrate this difference:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'{self.name} is {self.age} years old.'

    def __repr__(self):
        return f'Person({self.name}, {self.age})'

p = Person('John', 30)

print(p)  # John is 30 years old.
p  # Person(John, 30)

Here, print(p) invokes the __str__ method and returns a human-readable string. However, when you type p in the console, Python calls the __repr__ method and returns a more detailed string that could be used to recreate the object.

Why and When to Use __str__

The __str__ method is primarily used for creating a human-readable representation of the object. It's a great way to provide a simple summary or description of the object that can easily be understood by end users.

You might want to use __str__ when you're printing objects for logging or debugging purposes, or when you want to display a friendly message to the user. For example, if you're developing a game, you might use __str__ to print a player's stats in a readable format.

Here's how you might use __str__ in a game:

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

class Player:
    def __init__(self, name, level, health):
        self.name = name
        self.level = level
        self.health = health

    def __str__(self):
        return f'Player {self.name} is at level {self.level} with {self.health} health points.'

player = Player('Hero', 10, 100)

print(player)  # Player Hero is at level 10 with 100 health points.

In this example, the __str__ method returns a string that provides a concise summary of the player's current status. This makes it easy for users to understand the player's status at a glance.

Why and When to Use __repr__

The __repr__ method in Python is a special method that returns a string representing a printable version of an object. But when would you use it? Well, __repr__ is intended to be unambiguous and complete. This means that if you have an object, the __repr__ of that object should contain all the information necessary to recreate the object if fed back into the interpreter.

This makes __repr__ incredibly useful for debugging and logging, as it can provide a more detailed overview of an object compared to __str__. If you're working with complex data structures, or need a complete representation of your object for troubleshooting, __repr__ is the way to go.

Note: In the absence of a defined __str__ method, Python will default to using __repr__ when the print() function is called on an object.

Examples: Using the __str__ Method

Now that we've discussed the __repr__ method, let's switch gears and look at some examples of how you might use the __str__ method in Python. Remember, __str__ is meant to return a nicely printable string representation of an object, making it great for end-user output.

Let's define a simple Person class with __str__ method:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'Person(name={self.name}, age={self.age})'

Now, let's create an instance of Person and print it:

p = Person('John', 28)
print(p)

Output:

Person(name=John, age=28)

As you can see, the print() function calls the __str__ method and prints a user-friendly string representation of our Person object. This can be very useful when you want to present object information in a readable and clean format.

Examples: Using the __repr__ Method

Let's dive into some examples to understand the usage of repr in Python. Consider a class called "Person" with a few attributes.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

If we create an instance of this class and try to print it, we'll get an unhelpful message.

p = Person('John Doe', 30)
print(p)

Output:

<__main__.Person object at 0x7f3f8e7e3d30>

This is where repr comes in handy. Let's override the repr method in our class.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f'Person(name={self.name}, age={self.age})'

Now, when we create an instance of the class and print it, we get a much more meaningful output.

p = Person('John Doe', 30)
print(p)

Output:

Person(name=John Doe, age=30)

The __repr__ method should return a string that is a valid Python expression. It's meant to be unambiguous and complete. This means that if you were to copy its output and run it, you should get the same object that was printed.

Conclusion

__str__ and __repr__ are special methods in Python that allow us to control how objects are converted to strings. While __str__ is meant for creating a readable string representation for end users, __repr__ is designed to generate an unambiguous string representation for developers. Understanding the difference between these two methods and when to use each one is crucial for writing clean, effective Python code.

Whether you're debugging or displaying data, these magic methods can make your life a lot easier. Remember, it's always a good practice to implement __repr__ for your classes, and implement __str__ if you think it would be useful to have a string version of the object that's user-friendly.

Last Updated: August 27th, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms