I've come across an example of weird behavior when transitioning some code from python 2 to python 3. Below's a minimal (?) example of it:
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))
when run with python2
, this code produces some output (a hash of Bar(1)
), while python3
causes a TypeError: unhashable type: 'Bar'
this means that __hash__
is somehow inherited (from object
?) in python 2.
So, my questions are: what is the hash of Bar(1)
in python 2? And why is the behaviour different?
Yes, the data model has changed. In Python 3:
So, since you've defined a
__eq__
explicitely, but did not define a__hash__
, Python 3 objects will implicitely have__hash__ = None
, causing the objects to be unhashableIn Python 2:
So it is hashing based on identity, which is a problem, because it isn't consistent with your
__eq__
. This is a reason that Python 3 switched behaviors.From https://docs.python.org/3/reference/datamodel.html#object.hash
See https://docs.python.org/2/reference/datamodel.html#object.hash for the Python 2 version.