ProgrammingBackend Developer

What are magic methods (dunder methods) in Python, how are they used, and why should they be overridden in custom classes? Provide examples of their usage and explain the nuances that are important to consider when implementing them.

Pass interviews with Hintsage AI assistant

Answer.

Magic methods (or dunder methods – from double underscore) are special methods whose names begin and end with double underscores, for example, __init__, __str__, __add__. They allow you to integrate instances of your own classes into the syntax and behavior of Python: define reactions to arithmetic operations, comparisons, string conversions, work with collection protocols, etc.

Example:

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"Vector({self.x}, {self.y})" v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) # Calls v1.__add__(v2), returns Vector(4, 6)

Trick Question.

If you do not implement __eq__ in your own class, how will its instances be compared using the == operator?

Answer: By default, the == operator compares objects by identity (memory address, similar to the is operator) unless the magic method __eq__ is overridden.

class A: pass print(A() == A()) # False, even though the objects "seem identical"

Examples of real mistakes due to ignorance of the subtleties of the topic.


Story

In a project where it was necessary to compare graph structures, the __eq__ method was not implemented. As a result, when checking "is the node already added," an incorrect result was obtained because the == operator compared objects by id, not by content.


Story

When writing a REST API, an object was serialized into a string for logging via str(obj), but the __str__ was not defined. As a result, an unreadable text <MyObj object at 0x...> was output, which complicated the diagnosis of issues.


Story

In a library for mathematical computations, only __add__ was implemented, but __iadd__ for the += operator was forgotten. Consequently, the expression v += w did not work as expected (a new object was created, the old one was not updated), leading to memory leaks in complex computations.