John Millikin은 다음과 유사한 솔루션을 제안했습니다.
class A(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
return (isinstance(othr, type(self))
and (self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
def __hash__(self):
return hash((self._a, self._b, self._c))
이 솔루션의 문제점은입니다 hash(A(a, b, c)) == hash((a, b, c))
. 다시 말해, 해시는 주요 멤버의 튜플의 해시와 충돌합니다. 어쩌면 이것이 실제로 자주 문제가되지 않습니까?
업데이트 : Python 문서는 위의 예와 같이 튜플을 사용하는 것이 좋습니다. 설명서에 나와 있습니다.
유일하게 필요한 속성은 동일하게 비교되는 객체의 해시 값이 동일하다는 것입니다
그 반대는 사실이 아닙니다. 동일하게 비교되지 않은 객체 는 동일한 해시 값을 가질 수 있습니다. 이러한 해시 충돌 로 인해 객체가 동일하게 비교되지 않는 한 dict 키 또는 세트 요소 로 사용될 때 한 객체가 다른 객체를 대체 하지 않습니다 .
오래된 / 나쁜 솔루션
에 파이썬 문서는__hash__
XOR 같은 것을 사용하여 하위 구성 요소의 해시를 결합하는 제안 이 우리에게주는 :
class B(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
def __eq__(self, othr):
if isinstance(othr, type(self)):
return ((self._a, self._b, self._c) ==
(othr._a, othr._b, othr._c))
return NotImplemented
def __hash__(self):
return (hash(self._a) ^ hash(self._b) ^ hash(self._c) ^
hash((self._a, self._b, self._c)))
업데이트 : Blckknght가 지적했듯이 a, b 및 c의 순서를 변경하면 문제가 발생할 수 있습니다. ^ hash((self._a, self._b, self._c))
해시되는 값의 순서를 캡처하기 위해 추가 기능 을 추가했습니다 . 이 마지막이 ^ hash(...)
되는 조합 된 값을 재 배열 할 수없는 경우에 제거 될 수있다 (예를 들어, 따라서 서로 다른 유형 및 값이있는 경우 _a
에 할당되지 않을 _b
또는 _c
등).
__key
함수 를 분해 할 때 발생하는 사소한 오버 헤드 외에도 해시 속도만큼이나 빠릅니다. 물론 속성이 정수로 알려져 있고 그 수가 너무 많지 않으면 홈 롤링 해시로 약간 더 빠르게 실행될 수 있지만 잘 분산되지는 않았을 것입니다. small 의 생성 이 특별히 최적화 되어hash((self.attr_a, self.attr_b, self.attr_c))
놀랍게도 빠르고 정확tuple
하며 해시를 C 내장으로 가져오고 결합하는 작업을 추진합니다. 일반적으로 Python 레벨 코드보다 빠릅니다.