In class and objects, dunder str ( __ str __( ) ) and dunder repr ( __ repr __( ) ) built-in functions, also known as magic functions are used to return the string representation of the object. If both of them return strings, then what’s the difference between them?

Firstly, let’s see what these functions returns when they are not defined in the class.

# Creating a class named Addition
class Addition:

    def __init__(self,num1,num2):
        self.num1 = num1
        self.num2 = num2
        
    def Add(self):
        add = self.num1+self.num2
        return add
   
# Creating an object of Addition class
a = Addition(3,4) 

print(a.__str__)
print(a.__repr__)

Output

<method-wrapper '__str__' of Addition object at 0x0000024EB29404A8>
<method-wrapper '__repr__' of Addition object at 0x0000024EB29404A8>

As you can see, both simply tells us that it’s an instance object of the class Addition at the some memory address which is same for both the methods.

Now, let’s define __ str __ ( ) in our class.

class Addition:

    def __init__(self,num1,num2):
        self.num1 = num1
        self.num2 = num2

    def __str__(self):
        add = self.num1+self.num2
        return str(add)

    def Add(self):
        add = self.num1+self.num2
        return add
   
# Creating an object of Addition class
a = Addition(3,4) 
print(a)           # dunder str will be called
a                  # this will return an address

Output

7
<__main__.Addition at 0x24eb2940da0>

The __ str __( ) method will be called when print( ) is invoked while on calling the object a it simply returns the address. Interesting right? Now, let’s remove the __ str __( ) method and define __ repr __( ) in the class and see the results.

class Addition:

    def __init__(self,num1,num2):
        self.num1 = num1
        self.num2 = num2

    def __repr__(self):
         add = self.num1+self.num2
         return str(add)

    def Add(self):
        add = self.num1+self.num2
        return add
   
# Creating an object of Addition class
a = Addition(3,4) 
print(a)        # dunder repr will be called
a               # dunder repr will be called

Output

7
7

Basically, what happens is when str is not defined, then it will call repr. The repr returns a string that by default describes the pointer of the object.

Let’s see what happens when both the methods are defined in the class?

class Calci:
    
    def __init__(self,num1,num2):
        self.num1 = num1
        self.num2 = num2
        
    def __repr__(self):
        add = self.num1+self.num2
        return str(self.num1)
            
    def __str__(self):
        add = self.num1+self.num2
        return str(add)
        
    def Add(self):
        add = self.num1+self.num2
        return add
    
c = Calci(3,4)     # Creating an object c of class Calci
print(c)           # this will call __str__()
print([c])         # this will call __repr__()
c                  # this will also  call __repr__()

Output

7
[3]
3

When print(c) is invoked __ str __( ) was called, when print([c]) is invoked __ repr __( ) was called, whereas when we just inspected the object c, __ repr __( ) was called.

Both str and repr functuions are used to return the string representation of the object. When we just inspect the object, __ repr__( ) will be called while __ str __( ) is called when print( ) is invoked. When __ str __( ) is not defined, then it will call __ repr __( ) . The __ repr __( ) returns a string that by default describes the pointer of the object. Moreover, __ str __( ) should always return a string, whereas the __ repr __( ) can return any valid Python expression.

CONCLUSION

__ str __ ( ) is used for creating output that is mainly for end-users to show the descriptive information of the object from an end user’s perspective in terms of what data the object contains. Whereas __ repr __( ) shows the unambiguous information of the object from a developer’s perspective in terms of how the object can be constructed.