Типы, определяющие `__eq__`, не подлежат анализу?

У меня была странная ошибка при переносе функции в виджет 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__.) Как я могу обойти это?

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

Акцент мой.

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

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

Ответ 4

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

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