Phase 7 of 25 · Topic 7.2

Dunder Magic Methods (__repr__, __str__, __eq__, __hash__)

1Concept

Dunder (double underscore) methods implement standard Python object behaviors: `__repr__` provides an unambiguous developer representation; `__str__` provides user-friendly text; `__eq__` determines equality; `__hash__` enables storing instances in sets and dictionary keys.

2Architecture Diagram

obj == other  ---> Calls obj.__eq__(other)
hash(obj)     ---> Calls obj.__hash__() (Must remain constant for set/dict keys!)

3Code Example

Python 3.12
class ServerNode:
    def __init__(self, node_id: str, ip: str):
        self.node_id = node_id
        self.ip = ip

    def __repr__(self):
        return f"ServerNode(node_id={self.node_id!r}, ip={self.ip!r})"

    def __eq__(self, other):
        if not isinstance(other, ServerNode):
            return False
        return self.node_id == other.node_id

    def __hash__(self):
        return hash(self.node_id)

node1 = ServerNode("node-01", "192.168.1.10")
node2 = ServerNode("node-01", "10.0.0.5") # Same node_id

cluster = {node1, node2}
print(f"Cluster set: {cluster}")
print(f"Node representation: {repr(node1)}")

4Expected Output

Cluster set: {ServerNode(node_id='node-01', ip='192.168.1.10')}
Node representation: ServerNode(node_id='node-01', ip='192.168.1.10')

5Key Takeaways

  • If a class overrides `__eq__` without defining `__hash__`, Python sets `__hash__ = None` (unhashable).
  • Always ensure `__hash__` uses immutable fields that do not change over the object's lifetime.
  • `__repr__` should ideally look like valid Python code to recreate the object.