Типы, определяющие `__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__
?:)