Мне назвали класс GraphEdge
который я хотел бы быть исключительно определенным в наборе (встроенное set
введите) tail
и head
участники, которые установлены через __init__
.
Если я не определяю __hash__
, Я вижу следующее поведение:
>>> E = GraphEdge('A', 'B')
>>> H = GraphEdge('A', 'B')
>>> hash(E)
139731804758160
>>> hash(H)
139731804760784
>>> S = set()
>>> S.add(E)
>>> S.add(H)
>>> S
set([('A', 'B'), ('A', 'B')])
Набор не имеет никакого способа знать это E
и H
то же по моему определению, так как у них есть отличающиеся хеши (который является тем, что использование типа набора определить уникальность, к моему знанию), таким образом, это добавляет обоих как отличные элементы. Таким образом, я определяю довольно наивную хеш-функцию для GraphEdge
как так:
def __hash__( self ):
return hash( self.tail ) ^ hash( self.head )
Теперь вышеупомянутые работы как ожидалось:
>>> E = GraphEdge('A', 'B')
>>> H = GraphEdge('A', 'B')
>>> hash(E)
409150083
>>> hash(H)
409150083
>>> S = set()
>>> S.add(E)
>>> S.add(H)
>>> S
set([('A', 'B')])
Но ясно, ('A', 'B')
и ('B', 'A')
в этом случае возвратит тот же хеш, таким образом, я ожидал бы, что не мог добавить ('B', 'A')
к набору, уже содержащему ('A', 'B')
. Но это не то, что происходит:
>>> E = GraphEdge('A', 'B')
>>> H = GraphEdge('B', 'A')
>>> hash(E)
409150083
>>> hash(H)
409150083
>>> S = set()
>>> S.add(E)
>>> S.add(H)
>>> S
set([('A', 'B'), ('B', 'A')])
Таким образом, тип набора использует хеш или нет? Если так, как последний сценарий возможен? В противном случае, почему не делает первого сценария (нет __hash__
определенный) работа? Я пропускаю что-то?
Править: Для ссылки для будущих читателей я уже имел __eq__
определенный (также на основе tail
и head
).
У вас есть хеш-стол. На хеш-столкновения набор использует оператор == для проверки того, по-настоящему равен ли они друг другу.
Важно понимать, как хэш и == работает вместе, потому что оба используются наборами. Для двух значений X и Y важное правило состоит в том, что:
x == y ==> hash(x) == hash(y)
(x равен y, подразумевает, что хэши X и Y равны). Но обратный не соответствует действительности: два неравных ценностях могут иметь то же самое хеш.
Наборы (и Dicts) будут использовать хеш, чтобы получить приближение к равенству, но будет использовать реальное равенство, чтобы понять, если два значения одинаковы или нет.
Вы всегда должны определять оба __ (] __ ()
и __ хэш __ ()
Если вам нужен хотя бы один из них. Если хэси двух объектов равны, проводится дополнительный __ __ __ ()
для проверки уникальности.