magic dunder methods

Magic / Dunder Methods in Python

Magic or dunder methods are special methods in Python OOPs that enrich your classes. It is also known as dunder methods. These methods are distinguished from other methods in a special way by using double underscore before and after the method name.

This method allows instances of a class to interact with the built-in functions and operators. The name “dunder” comes from “double underscore”. Simply it can be thought as a contract between your implementation and Python interpreter. Main terms of the contract is Python performing some actions behind the scenes under given circumstances. It is used in operator overloading.

Why the name magic methods?

Here you don’t need to call them directly as you do for other methods. Python calls them for you internally from the class on certain action. For example, when adding two numbers using + operator, python calls __add__() method internally.

Well known Dunder method: __init__()

If you have already used class in Python then you might have seen __init__() method. Constructors in Python are dunder methods.  Its used to pass initial arguments to Python class. It is used for object initialization.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
p = Point(10,5)
print(p)  

Gives output as

<__main__.Point object at 0x00000205182133A0>

When __init__() method is invoked, the object here point is passed as self. Other arguments used in the method call are passed as the rest of the arguments to the function.

It just returns the memory address of the object point. For object representation we have __repr__() and __str__() methods.

__repr__():

It is the official or formal string representation of objects.

class Point:      
    def __init__(self, x, y):
        self.x = x
        self.y = y     
    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"

p = Point(10,5)
print(p)
Output:
Point(x=10, y=5)

This gives the name of class and value of properties of the class. The goal here is to be unambiguous. Very helpful in debugging.

__str__():

It is used for informal string representation of object. If not implemented, __repr__ will be used as a fallback. Here goal is to be readable.

class Point:   

    def __init__(self, x, y):

        self.x = x

        self.y = y

    def __str__(self):

        return f"Point(x={self.x}, y={self.y})"

p = Point(10,5)

print(p)
Output:
Point(x=10, y=5)

when you call print() it first looks for __str__() to see if it’s been defined otherwise it calls __repr__().

__new__():

When you create an instance of a class, Python first calls the __new__() method to create the object and then calls the __init__() method to initialize the object’s attributes. It is a static method of the object class.

class SquareNumber(int):
    def __new__(cls, value):
        return super().__new__(cls, value ** 2)
x = SquareNumber(3)
print(x)
Output:

9

__add__():

The magic method __add()__ performs the addition of the specified attributes of the objects. Internally, the addition of these two distance objects is desired to be performed using the overloading + operator.

class concat:
  
    def __init__(self, val):
        self.val = val
          
    def __add__(self, val2):
        return concat(self.val + val2.val)
  
obj1 = concat("Hello")
obj2 = concat("Abaython")
obj3 = obj1 + obj2
print(obj3.val)
Output:
HelloAbaython

Magic or dunder methods are useful to emulate behaviour of built-in types to user defined objects and is core Python feature that should be used as needed. 

Points to note:

  • The __init__() method is automatically invoked during the time of the creation of an instance of a class. It is called a magic method because it is called automatically by Python.
  • This __repr__ magic method is used to represent a class instance in a string and it returns the string representation of the value supplied.
  • The __new__() magic method is implicitly called before the __init__() method. It returns a new object, which is then initialized by __init__().
  • The built-in str() function returns a string from the object parameter and it internally calls the __str__() method defined in the int class.
  • The __add()__ method is called internally when you use the + operator to add two numbers or for concatenation of strings