Explanation needed regarding explanation of hashab

2019-03-26 03:16发布

问题:

Mark Ransom answered on a SO question about hashes here in SO:

[...] An object is hashable if it has a hash value which never changes during its lifetime. So by the official definition, anything mutable can't be hashable, even if it has a __hash__() function. My statement about both requirements being necessary is untrue, because being hashable already implies the requirement to be immutable.

I want to make sure, that I got that right - even as a non native speaker - so I hope someone corrects me if I got it wrong.

Assuming this class

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))

I understand, that __eq__ allows me to compare objects of this class with the == operator. From Marks answer I understand, that even if my object peter = Author(1, "Peter", 33) has a __hash__ it is not hashable because I potentially could do something like peter.age = 43 which means it is not immutable. So my objects of the class Author are not hashable and therefore not usable as keys in dictionarys for example? Did I get right or does it seem, that I need more explanation? :-)

回答1:

Instances of this class are hashable if you promise never to reset id or name on them. You can't guarantee that these attributes will never be reset, by the Python principle that "we are all consenting adults here", but it would be very bad style to offer methods that reset the attributes that __hash__ relies on.

E.g., if you offer a set_name method on instances of Author, but no set_id, then clients of the class can reasonably presume that __hash__ operates only on the id.

If you want to make it clear to clients of Author that they should not reset some attribute, you can label it private by prepending an _ to its name. If you then still want to offer (read-only) access to the attribute using its common name, you can make it a property:

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))


标签: python hash