Given the following example,
class A(object):
pass
a = A()
a.x = 1
Obviously a is mutable, and then I put a in a set,
set([a])
It succeeded. Why I can put mutable object like "a" into a set/dict? Shouldn't set/dict only allow immutable objects so they can identify the object and avoid duplication?
the
id
does not change when you add members. so there is no reason for that not to work.Python doesn't test for mutable objects, it tests for hashable objects.
Custom class instances are by default hashable. That's fine because the default
__eq__
implementation for such classes only tests for instance identity and the hash is based of the same information.In other words, it doesn't matter that you alter the state of your instance attributes, because the identity of an instance is immutable anyway.
As soon as you implement a
__hash__
and__eq__
method that take instance state into account you might be in trouble and should stop mutating that state. Only then would a custom class instance no longer be suitable for storing in a dictionary or set.After doing some more research, I was able to find out the reason why I would think set and dict only allow immutable objects as the entries and keys respectively, which is incorrect. I think it's important for me to clarify that here as I'm sure there are people who are new to Python having the same doubt as I had before. There are two reasons for me to previously confuse immutability with hashability. First reason is that all the built-in immutable objects (tuple, frozenset...) are allowed as set entries or dict keys, while all of the built-in mutable container objects are not. Second reason is actually where this question was derived from. I was reading the book Mastering Object-Oriented Python. In the part it explains the
__hash__
function, it leads the reader into thinking immutability is the prerequisite of hashability.The definition of immutability is for an object, after its creation, you can't change the value of its existing attributes or creating new ones. So it has nothing to do with hashability, which requires an object to have their
__hash__()
and__eq__()
methods defined, and their hash value to be immutable during their lifecycle. Actually hashable objects are immutable in terms of their hash value. I guess that's one of the reason these two concepts get confused so often.From the docs the requirement are that it must be hashable and can be compared:
You can see from the last part that user defined classes (emphasis is mine) are hashable by default
There is no mention in the docs about mutability requirements for
set
:For a
dict
again the requirement is that the key is hashable: