I'm Able To Use A Mutable Object As A Dictionary Key In Python. Is This Not Disallowed?
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 toNone
. When the__hash__()
method of a class isNone
, instances of the class will raise an appropriateTypeError
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?"