Modules -> OOP -> Dunder methods -> The str method

The str method


Related code
class Dog:
    """Represents a dog.

    attributes: name: str, age: int, energy: float
    """

    def __init__(self, name, age, energy):
        self.name = name
        self.age = age
        self.energy = energy

    def print(self):
        print(f'Name: {self.name}, Age: {self.age}')

Most of the time we tend to print objects using print function. If we try to use it to print a dog, we don't see much useful information:

>>> murki = Dog("Murki", 2, 50)
>>> print(murki)
<Dog object at 0x000002603EDF0110>
>>>

The str method is a special method, like init, that is supposed to return a string representation of an object and is invoked whenever print or str functions are applied to the object. Its full name is__str__ (two underscore characters, followed by str, and then two more underscores).

class Dog:
    ...

    def __str__(self):
        return "Test"

    ...
>>> rks = Dog("Reksi", 1, 90)
>>> print(rks)
Test
>>> str(rks)
Test
>>>

So, in both cases, print and str, Test is printed, which means that Python runs __str__ method when these two functions are applied upon the instance.

__str__ should always return a string

It should not print it:

class Dog:
    def __str__(self):
        print("Test") # Wrong

and it should not return non string values, like in the below example, a tuple:

class Dog:
    def __str__(self):
        return self.name, self.age, self.energy  # Wrong

Let's say that whenever we print a dog we want to see dog's name and age, which is actually the implementation of Dog's print method. So we should just change its name and instead of printing the string we return it:

class Dog:
    """Represents a dog.

    attributes: name: str, age: int, energy: float
    """

    def __init__(self, name, age, energy):
        self.name = name
        self.age = age
        self.energy = energy

    def __str__(self):
        return f'Name: {self.name}, Age: {self.age}'
>>> rks = Dog("Reksi", 1, 90)
>>> print(rks)
Name: Reksi, Age: 1

When I write a new class, I almost always start by writing __init__, which makes it easier to instantiate objects, and __str__, which is useful for debugging.