Hashability questions

Christian Heimes lists at cheimes.de
Tue May 15 05:25:45 EDT 2012


Am 15.05.2012 07:27, schrieb Ian Kelly:
> Why?  I can't see any purpose in implementing __eq__ this way, but I
> don't see how it's "broken" (assuming that __hash__ is actually
> implemented somehow and doesn't just raise TypeError).  The
> requirement is that if two objects compare equal, then they must have
> the same hash, and that clearly holds true here.
> 
> Can you give a concrete example that demonstrates how this __eq__
> method is dangerous and broken?

Code explains more than words. I've created two examples that some issues.

Mutable values break dicts as you won't be able to retrieve the same
object again:

>>> class Example(object):
...     def __init__(self, value):
...         self.value = value
...     def __hash__(self):
...         return hash(self.value)
...     def __eq__(self, other):
...         if not isinstance(other, Example):
...             return NotImplemented
...         return self.value == other.value
...


>>> ob = Example("egg")
>>> d = {}
>>> d[ob] = True
>>> d["egg"] = True
>>> d["spam"] = True
>>> ob in d
True
>>> d
{'egg': True, <__main__.Example object at 0x7fab66cb7450>: True, 'spam':
True}

>>> ob.value = "spam"
>>> ob in d
False
>>> d
{'egg': True, <__main__.Example object at 0x7fab66cb7450>: True, 'spam':
True}


When you mess up __eq__ you'll get funny results and suddenly the
insertion order does unexpected things to you:

>>> class Example2(object):
...     def __init__(self, value):
...         self.value = value
...     def __hash__(self):
...         return hash(self.value)
...     def __eq__(self, other):
...         return hash(self) == hash(other)
...
>>> d = {}
>>> ob = Example2("egg")
>>> d[ob] = True
>>> d
{<__main__.Example2 object at 0x7fab66cb7610>: True}
>>> d["egg"] = True
>>> d
{<__main__.Example2 object at 0x7fab66cb7610>: True}
>>> d2 = {}
>>> d2["egg"] = True
>>> d2[ob] = True
>>> d2
{'egg': True}





More information about the Python-list mailing list