Метод хэша класса Python и set [дубликат]
этот вопрос уже есть ответ здесь:
Я использую set()
и __hash__
метод python
класс для предотвращения добавления одного и того же хэш-объекта в set. Согласно документ модели данных 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
мой вопрос: почему одни и те же объекты хэша не совпадают в наборе?
2 ответов
ваше чтение неверно. The __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
наборы нужны два методы, чтобы сделать объект hashable: __hash__
и __eq__
. Два примера должны возвращает то же значение хэша, когда они считаются равными. Экземпляр считается уже присутствующим в наборе, если оба хэша присутствуют в наборе и экземпляр считается равным одному из экземпляров с тем же хэшем в наборе.
ваш класс не реализует __eq__
, поэтому по умолчанию object.__eq__
используется вместо этого , который возвращает true только если obj1 is obj2
тоже верно. Другими словами, два экземпляра считаются равными, только если они тот же самый экземпляр.
только потому, что их хэши совпадают, не делает их уникальными, насколько это касается набора; даже объекты с разными хэшами могут оказаться в одном слоте хэш-таблицы, как модуль хэша против размера таблицы используется.
Добавить свой пользовательский __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