Skip to content Skip to sidebar Skip to footer

I'm Able To Use A Mutable Object As A Dictionary Key In Python. Is This Not Disallowed?

class A(object): x = 4 i = A() d = {} d[i] = 2 print d i.x = 10 print d I thought only immutable objects can be dictionary keys, but the object i above is mutable.

Solution 1:

Any object with a __hash__ method can be a dictionary key. For classes you write, this method defaults to returning a value based off id(self), and if equality is not determined by identity for those classes, you may be surprised by using them as keys:

>>>classA(object):...def__eq__(self, other):...returnTrue...>>>one, two = A(), A()>>>d = {one: "one"}>>>one == two
True
>>>d[one]
'one'
>>>d[two]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: <__main__.A object at 0xb718836c>

>>>hash(set())  # sets cannot be dict keys
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

Changed in version 2.6: __hash__ may now be set to None to explicitly flag instances of a class as unhashable.

classUnhashable(object):
  __hash__ = None

Solution 2:

An object kan be a key in a dictionary if it is hashable.

Here is the definition of hashable from the documentation:

An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() or__cmp__() method). Hashable objects which compare equal must have the same hash value.

Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

All of Python’s immutable built-in objects are hashable, while no mutable containers (such as lists or dictionaries) are. Objects which are instances of user-defined classes are hashable by default; they all compare unequal, and their hash value is their id().

Since object provides a default implementation of __hash__, __eq__ and __cmp__ this means that anything deriving from object is hashable unless it is explicitly defined not to be hashable. It is not disallowed to create a mutable type that is hashable, but it might not behave as you want.

Solution 3:

The requirement is that the hash of an object doesn't change over time, and that it keeps comparing equal (==) with its original value. Your class A meets both these requirements, so it makes a valid dictionary key. The x attribute is not considered at all in keying, only the object identity is.

Solution 4:

@fred-nurk's example above luckily no longer works in Python 3, because of this change:

A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None. When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError when a program attempts to retrieve their hash value...

Thank God for that. However, if you explicitly define __hash__() for yourself, you can still do evil things:

classBadHasher:
    def__init__(self):
        self.first = True# Implement __hash__ in an evil way. The first time an instance is hashed,# return 1. Every time after that, return 0.def__hash__(self):
        if self.first:
            self.first = Falsereturn1return0

myobject = BadHasher()
# We can put this object in a set...
myset = {myobject}
# ...but as soon as we look for it, it's gone!if myobject notin myset:
    print("what the hell we JUST put it in there")

Post a Comment for "I'm Able To Use A Mutable Object As A Dictionary Key In Python. Is This Not Disallowed?"