Типы, которые определяют `__eq__`, недоступны для чтения? - PullRequest
61 голосов
/ 22 октября 2009

У меня была странная ошибка при переносе функции на развилку Python 3.1 моей программы. Я сузил это до следующей гипотезы:

В отличие от Python 2.x, в Python 3.x, если у объекта есть метод __eq__, он автоматически недоступен.

Это правда?

Вот что происходит в Python 3.1:

>>> class O(object):
...     def __eq__(self, other):
...         return 'whatever'
...
>>> o = O()
>>> d = {o: 0}
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    d = {o: 0}
TypeError: unhashable type: 'O'

Последующий вопрос: как мне решить мою личную проблему? У меня есть объект ChangeTracker, в котором хранится WeakKeyDictionary, указывающий на несколько объектов, для каждого из которых указывается значение их рассола в определенный момент времени в прошлом. Всякий раз, когда существующий объект регистрируется, трекер изменений сообщает, идентичен ли его новый пикл своему старому, и, следовательно, говорит, изменился ли объект за это время. Проблема в том, что теперь я даже не могу проверить, находится ли данный объект в библиотеке, потому что это заставляет его делать исключение из-за того, что объект не подлежит обработке. (Потому что у него есть метод __eq__.) Как я могу обойти это?

Ответы [ 4 ]

61 голосов
/ 22 октября 2009

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

Решение простое: просто определите __hash__ вместе с определением __eq__.

22 голосов
/ 22 октября 2009

Этот абзац от http://docs.python.org/3.1/reference/datamodel.html#object.hash

Если класс, который переопределяет __eq__() необходимо сохранить реализацию __hash__() из родительского класса, переводчик должен сказать это явно, установив __hash__ = <ParentClass>.__hash__. В противном случае наследование __hash__() будет заблокирован, как если бы __hash__ был явно установлен на Нет.

3 голосов
/ 22 октября 2009

Проверьте руководство по Python 3 на object.__hash__:

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

Акцент мой.

Если вы хотите быть ленивым, похоже, вы можете просто определить __hash__(self), чтобы вернуть id(self):

Пользовательские классы по умолчанию имеют методы __eq__() и __hash__(); с ними все объекты сравниваются неравно (кроме самих себя) и x.__hash__() возвращает id(x).

1 голос
/ 22 октября 2009

Я не эксперт по Python, но не имеет ли смысла, что, когда вы определяете eq-метод, вы также должны определить и хеш-метод (который вычисляет хеш-значение для объекта) В противном случае, механизм хеширования не будет знать, попадет ли он в тот же объект или в другой объект с таким же хеш-значением. На самом деле, все наоборот, возможно, в итоге вы вычислили бы разные значения хеш-функции для объектов, которые считаются равными вашему __eq__ методу.

Я понятия не имею, как называется эта хэш-функция, __hash__ возможно? :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...