Требуется объяснение относительно объяснения хеш-объектов - PullRequest
9 голосов
/ 11 июля 2011

Марк Рэнсом ответил на ТАК вопрос о хешах здесь, в СО:

[...] An Объект является хешируемым, если он имеет хеш-значение , которое никогда не изменяется во время его время жизни . Так что по официальному определению ничего мутабельного не может быть хэшируемым, даже если он имеет функцию __hash__(). Мое заявление о том, что оба требования необходимы, не соответствует действительности, потому что hashable уже подразумевает требование быть неизменным.

Я хочу убедиться, что я понял это правильно - даже не как носитель языка - поэтому я надеюсь, что кто-то исправит меня, если я ошибаюсь.

Предполагая, что этот класс

class Author(object):
    def __init__(self, id, name, age):
        self.id = id
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.id==other.id\
               and self.name==other.name

    def __hash__(self):
        return hash(('id', self.id,
                     'name', self.name))

Я понимаю, что __eq__ позволяет мне сравнивать объекты этого класса с оператором ==. Из ответа Маркса я понимаю, что даже если мой объект peter = Author(1, "Peter", 33) имеет __hash__, он не может быть хэшируемым, потому что я потенциально мог бы сделать что-то вроде peter.age = 43, что означает, что он не является неизменным. То есть мои объекты класса Author не являются хэшируемыми и поэтому не могут использоваться как ключи в словарях, например? Я понял правильно или мне кажется, что мне нужно больше объяснений? : -)

1 Ответ

11 голосов
/ 11 июля 2011

Экземпляры этого класса являются хэшируемыми, если вы обещаете никогда не сбрасывать id или name на них. Вы не можете гарантировать, что эти атрибуты никогда не будут сброшены, по принципу Python, что «мы все здесь взрослые по согласию» , но было бы очень плохим стилем предлагать методы, которые сбрасывают атрибуты, которые __hash__ опирается на

Например, если вы предлагаете метод set_name для экземпляров Author, но не set_id, то клиенты этого класса могут разумно предположить, что __hash__ работает только на id.

Если вы хотите дать понять клиентам Author, что им не следует сбрасывать какой-либо атрибут, вы можете пометить его как частный, добавив _ к его имени. Если вы все еще хотите предложить (только для чтения) доступ к атрибуту с помощью его общего имени, вы можете сделать его свойством :

class Author(object):
    def __init__(self, id, name, age):
        self._id = id
        self._name = name
        self.age = age      # ages tend to change, so mutable

    id = property(lambda self: self._id)
    name = property(lambda self: self._name)

    def __eq__(self, other):
        return self.id==other.id\
               and self.name==other.name

    def __hash__(self):
        return hash(('id', self.id,
                     'name', self.name))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...