When I attempt to print a dictionary (or its __dict__
), a KeyError is raised. The dict is a mapping from MyClass
instances to floats and ints.
It would be too lengthy to share the source code of MyClass
.
d = dict()
d[MyClass()] = 10.023
d[MyClass()] = 1.023
d[MyClass()] = 8
print(d)
Out[16]: ---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
c:\users\[...]\lib\site-packages\IPython\core\formatters.py in __call__(self, obj)
700 type_pprinters=self.type_printers,
701 deferred_pprinters=self.deferred_printers)
--> 702 printer.pretty(obj)
703 printer.flush()
704 return stream.getvalue()
[...]
618 p.pretty(key)
619 p.text(': ')
--> 620 p.pretty(obj[key])
621 p.end_group(step, end)
622 return inner
KeyError: <MyClass.subclass instance>
Also the following raises KeyError:
for key in d:
print(d[key])
Although some of the values are printed correctly before an error is raised. It seems to have trouble looking up some specific keys.
I think this is pretty weird too:
In [19]: [a in d for a in d]
Out[19]: [False, True, False, True, False]
Finally:
list(d) # works fine, just like d.keys() and d.values()
Out[19]: [<MyClass.subclass instance>,<MyClass.subclass instance>,<MyClass.subclass instance>,...]
d[list(d)[0]] # works fine
Out[20]: 10.023
d[list(d)[1]] # raises KeyError
list(d)[1] in d # returns False
list(d)[0] in d # returns True
I checked: - all keys have different hashes - list(d) contains no duplicates - list(d) instances which are correctly looked up have no noticeable difference (some are even instances of the same class) - List item
I cannot think of an explanation to this behaviour. It only manifested today.
I recently made some changes in the file structure of the module containing MyClass
. Before: MyClass
subclasses in the same file as MyClass
definition.
After: MyClass
subclasses in individual files in the same directory.
I cannot see how this could affect any of that, but who knows.
Under normal circumstances this should not happen.
However you can violate the dictionary contract that the keys must be immutable with respect to equality and hash. Because if the hash changes the objects cannot be found anymore.
Mapping Types — dict
[...]
A dictionary’s keys are almost arbitrary values. Values that are not hashable, that is, values containing lists, dictionaries or other mutable types (that are compared by value rather than by object identity) may not be used as keys.
To demonstrate what can happen when you use mutable objects with a hash-function that depends on values: Consider this class:
class Test:
def __init__(self, value):
self.value = value
def __hash__(self):
return self.value
And this little snippet:
>>> t1 = Test(1)
>>> d = {}
>>> d[t1] = 10
>>> t1.value = 2 # t1's hash also changes at this point
>>> d[t1]
KeyError: <__main__.Test object at 0x0000020FCA5AD748>
This is of course overly simplified but I suspect that something like this happens in your code. I propose you monitor changes to the values that are relevant for __hash__
and __eq__
during the program execution.