Метод хеширования по умолчанию в Python 2, а не Python 3 - PullRequest
1 голос
/ 18 апреля 2019

Я сталкивался с примером странного поведения при переходе некоторого кода с python 2 на python 3. Ниже приведен минимальный (?) Пример этого:


class Bar(object):
    def __init__(self, x):
        self.x = x
    def __eq__(self, other):
        return self.x == other.x

b = Bar(1)
print(hash(b))

при запуске с python2,этот код производит некоторый вывод (хеш Bar(1)), в то время как python3 вызывает TypeError: unhashable type: 'Bar'

, это означает, что __hash__ каким-то образом наследуется (от object?) в Python 2.

Итак, мои вопросы: что такое хэш Bar(1) в python 2?И почему поведение отличается?

Ответы [ 2 ]

3 голосов
/ 18 апреля 2019

Да, модель данных изменилась. В Python 3 :

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

Класс, который переопределяет __eq__() и не определяет __hash__() будет иметь __hash__() неявно установлен на None.Когда __hash__() метод класса равен None, экземпляры класса вызовут соответствующий TypeError, когда программа попытается получить их хэш-значение, и будут также правильно определены как не подлежащие обработке при проверке isinstance(obj, collections.abc.Hashable).

Итак, поскольку вы явно определили __eq__, но не определили __hash__, объекты Python 3 будут неявно иметь __hash__ = None, в результате чего объекты станут неисчерпаемыми

В Python 2 :

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

Так что это хэширование на основе идентичности, что является проблемой, потому что это нене соответствует вашему __eq__.Это причина того, что Python 3 переключил поведение.

2 голосов
/ 18 апреля 2019

С https://docs.python.org/3/reference/datamodel.html#object.hash

Класс, который переопределяет eq () и не определяет hash () хэш () неявно имеет значение None. Когда метод hash () класса None, экземпляры класса будут вызывать соответствующий TypeError, когда программа пытается получить их хэш-значение, и также будет правильно определен как не подлежащий уничтожению при проверке isinstance (obj, collection.abc.Hashable).

См. https://docs.python.org/2/reference/datamodel.html#object.hash для версии Python 2.

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