Instances of your C
class are actually hashable, it comes with a default implementation of __hash__
which pertains to the identity of that object:
>>> hash(c) # calls c.__hash__()
306169194
This __hash__
implementation allows your instance to be used as a key in a dictionary.
This explains "Why doesn't changing things in your class change the hash?" — because the identity/reference of the instance doesn't change even if its contents do.
On older versions of python, this used to be exactly equal to the object's id, but from python 3 onwards, it seems to be some derivative of it. This post goes into the gory details on the hash implementation.
Now let's say you wanted to prevent instances of your class from being used as a key... you could then do this (from the documentation):
If a class that does not override __eq__()
wishes to suppress hash support, it should include __hash__ = None
in the class definition.
class C:
def __init__(self):
self.val = 15
self.array = []
__hash__ = None # suppressing hash support
c = C()
And now you get a familiar sounding TypeError
if you attempt to retrieve the hash of c
:
>>> hash(c)
# TypeError: unhashable type: 'C'
Naturally, this also implies you cannot use c
as a dictionary key anymore (IOW trying to initialize {c: 15}
would also throw the same TypeError
since c
is not hashable).