두 인스턴스가 「같다」는 의미를 정의하려면 __eq__를, 그 인스턴스를 딕셔너리 키나 집합 요소로 쓰려면 __hash__를 정의해야 합니다.
두 메서드는 깊이 연관된 한 쌍입니다.
기본 동작.
파이썬의 기본 __eq__는 「is 비교」 — 같은 객체인가만 검사.
그래서 Point(3,4) == Point(3,4)가 False가 됩니다(메모리 주소가 다른 두 객체이므로).
「값이 같으면 같다」고 정의하려면 __eq__를 직접 정의해야 합니다.
__eq__ 정의.
class Point: def __eq__(self, other): if not isinstance(other, Point): return NotImplemented; return self.x == other.x and self.y == other.y.
NotImplemented를 반환하면 파이썬이 다른 시도(other.__eq__(self) 등)를 해 봅니다.
__hash__의 규칙.
__eq__를 정의하면 파이썬이 자동으로 __hash__를 None으로 설정해 「해시 불가」 객체로 만듭니다(딕셔너리 키·집합 요소로 쓸 수 없게).
해시 가능하게 하려면 __hash__도 함께 정의: def __hash__(self): return hash((self.x, self.y)).
보통 인스턴스의 핵심 속성을 튜플로 묶어 hash()에 넘깁니다.
황금 규칙: 「두 객체가 == 같으면 hash()도 같아야 한다」.
같은 「값」을 가진 두 객체가 다른 해시를 가지면 딕셔너리·집합이 잘못 동작합니다.
그래서 __eq__와 __hash__는 항상 함께, 같은 속성에 기반해 정의해야 합니다.
또 hashable이 되려면 객체가 「불변(immutable)」해야 합니다 — 해시 후에 속성이 바뀌면 안 됩니다.
한 줄 요약
__eq__로 두 인스턴스의 「같음」을, __hash__로 딕셔너리·집합에서 쓸 수 있게 합니다.
「==이면 hash도 같아야」 하는 황금 규칙을 지켜야 하며, dataclass(frozen=True)가 자동 처리합니다.
더 알아볼 것
- __eq__와 __hash__의 자동 생성
- __lt__·__gt__ — 정렬을 위한 비교
- total_ordering 데코레이터