September 11, 2024

Python Magic Methods

Magic methods in Python, also known as dunder methods (short for “double underscore”), are special methods with double underscores at the beginning and end of their names. These methods allow you to define how objects of your classes behave with Python’s built-in operations such as addition, subtraction, comparison, and more. Magic methods are a key part of Python’s object-oriented programming (OOP) capabilities.

1. Common Magic Methods

Below are some of the most commonly used magic methods in Python:

1.1. __init__(self, ...)

The __init__ method, known as the constructor, is called when an instance of a class is created. It allows you to initialize the object’s attributes.

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

p = Person("Alice", 30)
print(p.name, p.age)

1.2. __str__(self) and __repr__(self)

The __str__ method is called by the str() and print() functions to get a readable string representation of the object, while the __repr__ method is used by the repr() function and in the interactive interpreter for a more formal string representation.

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

    def __str__(self):
        return f"{self.name}, {self.age} years old"

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

p = Person("Alice", 30)
print(p)        # Calls __str__()
print(repr(p))  # Calls __repr__()

1.3. __len__(self)

The __len__ method is called by the len() function to return the length of an object.

class MyList:
    def __init__(self, items):
        self.items = items

    def __len__(self):
        return len(self.items)

my_list = MyList([1, 2, 3, 4])
print(len(my_list))

1.4. __add__(self, other)

The __add__ method allows you to define the behavior of the + operator for your objects.

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

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

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

p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2  # Calls __add__()
print(p3)

1.5. __eq__(self, other)

The __eq__ method allows you to define the behavior of the equality operator == for your objects.

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

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2)  # Calls __eq__()

1.6. __getitem__(self, key)

The __getitem__ method is used to get an item from an object using the indexing syntax.

class MyList:
    def __init__(self, items):
        self.items = items

    def __getitem__(self, index):
        return self.items[index]

my_list = MyList([10, 20, 30, 40])
print(my_list[2])  # Calls __getitem__()

1.7. __setitem__(self, key, value)

The __setitem__ method is used to set the value of an item using the indexing syntax.

class MyList:
    def __init__(self, items):
        self.items = items

    def __setitem__(self, index, value):
        self.items[index] = value

my_list = MyList([10, 20, 30, 40])
my_list[2] = 50  # Calls __setitem__()
print(my_list.items)

1.8. __delitem__(self, key)

The __delitem__ method is used to delete an item using the indexing syntax.

class MyList:
    def __init__(self, items):
        self.items = items

    def __delitem__(self, index):
        del self.items[index]

my_list = MyList([10, 20, 30, 40])
del my_list[2]  # Calls __delitem__()
print(my_list.items)

2. Other Useful Magic Methods

  • __call__(self, ...): Allows an object to be called as a function.
  • __contains__(self, item): Called by the in operator to check membership.
  • __iter__(self) and __next__(self): Used to make an object iterable.
  • __enter__(self) and __exit__(self, exc_type, exc_val, exc_tb): Used to define the behavior of a context manager (used in with statements).
  • __bool__(self): Allows you to define the behavior of your object when it is used in a Boolean context (e.g., in if statements).
  • __hash__(self): Defines the hash value for an object, used in hashing operations like when adding an object to a set or using it as a dictionary key.