Are instances of user-defined classes mutable?
David Lowry-Duda
david at lowryduda.com
Thu Aug 6 11:16:02 EDT 2020
On Thu, Aug 06, 2020 at 12:17:17PM +0800, ZHAOWANCHENG wrote:
> the doc of dictionary said "if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key."
> i think a instance of user-defined class is mutable, but i found it can be placed into a tuple that as a key of a dict:
> >>> class mycls(object):
> ... a = 1
> ...
> >>> me = mycls()
> >>> me.a = 2 # mutable?
> >>> {(1, me): 'mycls'}
> {(1, <__main__.mycls object at 0x0000022824DAD668>): 'mycls'}
> >>>
>
>
> So are instances of user-defined classes mutable or immutable?
A more specific description of objects that can be keys in a dictionary
can be found on the documentation:
https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
To be a key in a dictionary, an object must be *hashable*. The spec for
hashable objects is also in the documentation:
https://docs.python.org/3/glossary.html#term-hashable
In short, if a class implements __hash__() (which should never change
during an object's lifetime) and __eq__(), it can be hashable.
Many python builtins are hashable, but mutable builtins aren't. For
example lists aren't hashable.
To investigate a bit further, we might examine a particular example more
closely. In the code snippet that follows, we make two tuples with the
same data and two instances of a user-defined class with the same data.
We make a dictionary and see the difference between using tuples as keys
and instances of a user-defined class as keys.
```
tup1 = (1, 2)
tup2 = (1, 2)
d = dict()
d[tup1] = "one"
print(d[tup2]) # prints "one"
# Note that d "knows" tup1 and tup2 are "the same"
class myclass:
def __init__(self):
self.data = [1, 2]
myobj1 = myclass()
myobj2 = myclass()
print(myobj1.data == myobj2.data) # True
d[myobj1] = "spam"
print(d[myobj2]) # raises KeyError as myobj2 not in dictionary
# d doesn't "know" that myobj1 and myobj2 are "the same"
```
This difference in behavior is due to the default __hash__ and __eq__
methods for myclass, which don't consider the attributes of each
instance, whereas the hashing and comparison of tuples does consider the
contents of the tuple.
- DLD
--
David Lowry-Duda <david at lowryduda.com> <davidlowryduda.com>
More information about the Python-list
mailing list