Странный набор Python и поведение хеша - как это работает?

Мне назвали класс 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).

6
задан ezod 29 January 2010 в 01:18
поделиться

3 ответа

У вас есть хеш-стол. На хеш-столкновения набор использует оператор == для проверки того, по-настоящему равен ли они друг другу.

15
ответ дан 8 December 2019 в 03:39
поделиться

Важно понимать, как хэш и == работает вместе, потому что оба используются наборами. Для двух значений X и Y важное правило состоит в том, что:

x == y ==> hash(x) == hash(y)

(x равен y, подразумевает, что хэши X и Y равны). Но обратный не соответствует действительности: два неравных ценностях могут иметь то же самое хеш.

Наборы (и Dicts) будут использовать хеш, чтобы получить приближение к равенству, но будет использовать реальное равенство, чтобы понять, если два значения одинаковы или нет.

7
ответ дан 8 December 2019 в 03:39
поделиться

Вы всегда должны определять оба __ (] __ () и __ хэш __ () Если вам нужен хотя бы один из них. Если хэси двух объектов равны, проводится дополнительный __ __ __ () для проверки уникальности.

6
ответ дан 8 December 2019 в 03:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: