|
Original |
Translation |
|
117
|
Hash lists by their address (object ID). This doesn't work because if you construct a new list with the same value it won't be found; e.g.::
|
|
|
118
|
mydict = {[1, 2]: '12'} print(mydict[[1, 2]])
|
|
|
119
|
would raise a KeyError exception because the id of the ``[1, 2]`` used in the second line differs from that in the first line. In other words, dictionary keys should be compared using ``==``, not using :keyword:`is`.
|
|
|
120
|
Make a copy when using a list as a key. This doesn't work because the list, being a mutable object, could contain a reference to itself, and then the copying code would run into an infinite loop.
|
|
|
121
|
|
122
|
Mark lists as read-only once they are used as a dictionary key. The problem is that it's not just the top-level object that could change its value; you could use a tuple containing a list as a key. Entering anything as a key into a dictionary would require marking all objects reachable from there as read-only -- and again, self-referential objects could cause an infinite loop.
|
|
|
123
|
There is a trick to get around this if you need to, but use it at your own risk: You can wrap a mutable structure inside a class instance which has both a :meth:`__eq__` and a :meth:`__hash__` method. You must then make sure that the hash value for all such wrapper objects that reside in a dictionary (or other hash based structure), remain fixed while the object is in the dictionary (or other structure). ::
|
|
|
124
|
class ListWrapper: def __init__(self, the_list): self.the_list = the_list def __eq__(self, other): return self.the_list == other.the_list def __hash__(self): l = self.the_list result = 98767 - len(l)*555 for i, el in enumerate(l): try: result = result + (hash(el) % 9999999) * 1001 + i except Exception: result = (result % 7777777) + i * 333 return result
|
|
|
125
|
Note that the hash computation is complicated by the possibility that some members of the list may be unhashable and also by the possibility of arithmetic overflow.
|
|
|
126
|
Furthermore it must always be the case that if ``o1 == o2`` (ie ``o1.__eq__(o2) is True``) then ``hash(o1) == hash(o2)`` (ie, ``o1.__hash__() == o2.__hash__()``), regardless of whether the object is in a dictionary or not. If you fail to meet these restrictions dictionaries and other hash based structures will misbehave.
|
|