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? :-)
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))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With