Skip to main content

Advanced OOP

Python’s Hidden Spells

Imagine you’re a hacker who discovers secret commands in your toolkit like hidden spells that let you bend reality. In Python, these are called magic methods (also known as dunder methods, because they start and end with __). They allow you to customize how objects behave with built‑in operations like +, ==, or even print().

With operator overloading, you can redefine how operators work for your own classes. Suddenly, your objects can add, compare, or display themselves in ways that feel natural. This chapter is about learning how to wield these hidden spells to make your classes more powerful and intuitive.


Why Magic Methods Matter

  • Magic Methods: Special methods with double underscores (__init__, __str__, __add__, etc.) that Python calls automatically.
  • Operator Overloading: Redefining operators (+, -, *, ==) for custom classes.
  • Customization: Lets objects behave like built‑in types.
  • Readability: Makes code more intuitive and objects interact naturally with operators.
  • Real‑World Analogy: Think of customizing a universal remote. The same button (+) can increase volume on a TV or brightness on a monitor, depending on the device.

Common Magic Methods

    • Called when an object is created.
    • Defines how the object is displayed when printed.
    • Customizes == operator.

__eq__ – Equality Check

class Hacker:
    def __init__(self, name):
        self.name = name
    def __eq__(self, other):
        return self.name == other.name
print(Hacker("Shubham") == Hacker("Shubham"))  # True

__str__ – String Representation

class Hacker:
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return f"Hacker: {self.name}"
print(Hacker("Shubham"))

__init__ – Constructor

class Hacker:
    def __init__(self, name):
        self.name = name
h = Hacker("Shubham")

Operator Overloading

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

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

    def __str__(self):
        return f"({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(4, 5)
print(v1 + v2)  # (6, 8)
  • Why? The + operator now works naturally with Vector objects.

More Magic Methods

__call__: Makes objects callable like functions

class Greeter:
    def __call__(self, name):
        print(f"Hello, {name}!")
g = Greeter()
g("Shubham")  # Hello, Shubham!

__getitem__: Defines indexing behavior

class Team:
    def __init__(self, members):
        self.members = members
    def __getitem__(self, index):
        return self.members[index]
team = Team(["Shubham", "Aditi"])
print(team[0])  # Shubham

__len__: Defines behavior for len()

class Team:
    def __init__(self, members):
        self.members = members
    def __len__(self):
        return len(self.members)
print(len(Team(["Shubham", "Aditi"])))  # 2

Real‑World Example

class Account:
    def __init__(self, balance):
        self.balance = balance

    def __add__(self, other):
        return Account(self.balance + other.balance)

    def __str__(self):
        return f"Balance: {self.balance}"
acc1 = Account(1000)
acc2 = Account(500)
print(acc1 + acc2)  # Balance: 1500
  • Why? Operator overloading makes accounts behave naturally when combined.

The Hacker’s Notebook

  • Magic methods are Python’s special hooks that customize object behavior. Operator overloading lets objects interact naturally with +, ==, len(), and more.
  • Methods like __str__, __eq__, and __add__ make classes feel like built‑in types. Overloading improves readability and usability, turning custom objects into intuitive tools.

Hacker’s Mindset: treat magic methods as secret codes. With them, you bend Python’s rules to make your objects smarter, cleaner, and more powerful.


Tips, Tricks, Roadmaps, Resources, Networking, Motivation, Guidance, and Cool Stuff ♥

Updated on Jan 3, 2026