Python - класс __hash__ метод и набор

python python-3.x hash set python-datamodel

7499 просмотра

2 ответа

419 Репутация автора

Я использую set()и __hash__метод pythonкласса, чтобы предотвратить добавление того же хеш-объекта в набор. Согласно документу модели данных Python , set()рассмотрите тот же хеш-объект как тот же объект и просто добавьте их один раз.

Но он ведет себя иначе, как показано ниже:

class MyClass(object):

    def __hash__(self):
        return 0

result = set()
result.add(MyClass())
result.add(MyClass())

print(len(result)) # len = 2

Хотя в случае строкового значения он работает правильно.

result.add('aida')
result.add('aida')

print(len(result)) # len = 1

Мой вопрос: почему одни и те же хеш-объекты не совпадают в наборе?

Автор: Aida.Mirabadi Источник Размещён: 18.07.2016 06:54

Ответы (2)


5 плюса

770968 Репутация автора

Наборы нуждаются в двух методах, чтобы сделать объект хэшируемым: __hash__и __eq__. Два экземпляра должны возвращать одинаковое значение хеш - функции , когда они считаются равными. Экземпляр считается уже представленным в наборе, если в наборе присутствует как хеш, так и экземпляр считается равным одному из экземпляров с таким же хешем в наборе.

Ваш класс не реализуется __eq__, поэтому object.__eq__вместо него используется значение по умолчанию , которое возвращает true только в том случае, если obj1 is obj2также true. Другими словами, два экземпляра считаются равными, только если они точно совпадают .

То, что их хэши совпадают, не делает их уникальными в отношении набора; даже объекты с разными хэшами могут оказаться в одном слоте хеш-таблицы, так как используется модуль хеш-функции в зависимости от размера таблицы.

Добавьте свой пользовательский __eq__метод, который возвращает, Trueкогда два экземпляра должны быть равны:

def __eq__(self, other):
    if not isinstance(other, type(self)):
        return False
    # all instances of this class are considered equal to one another
    return True
Автор: Martijn Pieters Размещён: 18.07.2016 06:59

17 плюса

96078 Репутация автора

Решение

Ваше чтение неверно. __eq__Метод используется для проверки равенства. В документах просто утверждается, что __hash__значение также должно быть одинаковым для 2 объектов aи bдля которых a == b(то есть a.__eq__(b)) верно.

Это распространенная логическая ошибка: a == bбыть правдой означает, что hash(a) == hash(b)это тоже правда. Однако значение не обязательно означает эквивалентность , что в дополнение к предыдущему hash(a) == hash(b)будет означать это a == b.

Чтобы сделать все экземпляры MyClassсравнения равными друг другу, вам необходимо предоставить __eq__метод для них; в противном случае Python будет сравнивать их идентичности . Это может сделать:

class MyClass(object):
    def __hash__(self):
        return 0
    def __eq__(self, other):
        # another object is equal to self, iff 
        # it is an instance of MyClass
        return isinstance(other, MyClass)

В настоящее время:

>>> result = set()
>>> result.add(MyClass())
>>> result.add(MyClass())
1

В действительности вы должны основывать __hash__те свойства вашего объекта, которые используются для __eq__сравнения, например:

class Person
    def __init__(self, name, ssn):
        self.name = name
        self.ssn = ssn

    def __eq__(self, other):
        return isinstance(other, Person) and self.ssn == other.ssn

    def __hash__(self):
        # use the hashcode of self.ssn since that is used
        # for equality checks as well
        return hash(self.ssn)

p = Person('Foo Bar', 123456789)
q = Person('Fake Name', 123456789)
print(len({p, q})  # 1
Автор: Antti Haapala Размещён: 18.07.2016 06:59
Вопросы из категории :
32x32