How to Make a Python Class Hashable with __eq__ and __hash__
Define __eq__ and __hash__ together on a Python class so equal instances share the same hash and work correctly in sets and dictionary keys.
Python code
32 linesclass Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash((self.x, self.y))
def __repr__(self):
return f"Point({self.x}, {self.y})"
if __name__ == "__main__":
p1 = Point(1, 2)
p2 = Point(1, 2)
p3 = Point(3, 4)
print(f"p1 == p2: {p1 == p2}")
print(f"p1 == p3: {p1 == p3}")
print(f"hash(p1) == hash(p2): {hash(p1) == hash(p2)}")
points_set = {p1, p2, p3}
print(f"Set size (duplicates removed): {len(points_set)}")
print(f"Points in set: {points_set}")
lookup = Point(1, 2) in points_set
print(f"Point(1, 2) in set: {lookup}")
Output
p1 == p2: True
p1 == p3: False
hash(p1) == hash(p2): True
Set size (duplicates removed): 2
Points in set: {Point(3, 4), Point(1, 2)}
Point(1, 2) in set: True
How it works
Python requires that objects which compare equal (eq) also return the same hash value (hash). The hash method here builds a tuple of the x and y attributes and passes it to the built-in hash() function. This guarantees that two equal Point instances produce identical hashes, satisfying the hash invariant. The repr method makes instances print in a readable way when the set is displayed. Because both methods are defined together, Point objects work correctly as set members and dictionary keys.
Common mistakes
- Defining __eq__ without __hash__, which sets __hash__ to None and makes the class unhashable
- Returning NotImplemented instead of False when other is not a Point, which breaks symmetic equality checks
- Mutating x or y after the object is added to a set, corrupting its stored hash
Variations
- Use a dataclass with frozen=True, which auto-generates __eq__ and __hash__
- Store immutable attributes and skip setter methods to guarantee hash stability
Real-world use cases
- Storing unique geometry points in a set to deduplicate graph nodes from sensor data.
- Using dataclass-like entities as dictionary keys for caching precomputed results in a computation engine.
- Placing value objects into sets for fast membership checks in a trading order matching system.
Sponsored
More from OOP & classes
- Add property getter setter validation in Python easy
- Binary Tree Inorder Traversal in Python easy
- Borg pattern shared state in Python medium
- Bridge Pattern in Python: Separate Abstraction from Implementation medium
- Composable Predicates with the &, |, ~ Operators in Python medium
- Composition over Inheritance: How to Build a Wallet Account in Python easy
Keep learning
Related tutorials and quizzes for this topic.