Why must you define __hash__ when you define __eq__ for objects used in sets or as dict keys?
Objects that compare equal must have the same hash, or sets and dicts will treat them as different. Defining __eq__ without __hash__ sets __hash__ to None, so the class becomes unhashable. Base the hash on the same fields that __eq__ compares.
Explain it simply
A dictionary first uses the hash to choose a drawer, then uses == to find the item inside. If two equal objects hash to different drawers, the second one is never found. So the rule: if a == b, then hash(a) == hash(b).
Example
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __eq__(self, other):
return isinstance(other, Point) and (self.x, self.y) == (other.x, other.y)
def __hash__(self):
return hash((self.x, self.y))
print(Point(1, 2) == Point(1, 2)) # Output: True
print(len({Point(1, 2), Point(1, 2)})) # Output: 1
class Bad:
def __eq__(self, other):
return True
try:
{Bad()}
except TypeError:
print("unhashable") # Output: unhashableHash only fields that do not change, otherwise an object stored in a set can become impossible to find.
What to say in the interview
"Equal objects must have equal hashes. If I override __eq__ and not __hash__, Python sets __hash__ to None and the class can't go in sets or dict keys. I hash a tuple of the same fields used in __eq__, and I keep those fields immutable, or use a frozen dataclass."