Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can "k in d" be False, but "k in d.keys()" be True?

I have some python code that's throwing a KeyError exception. So far I haven't been able to reproduce outside of the operating environment, so I can't post a reduced test case here.

The code that's raising the exception is iterating through a loop like this:

for k in d.keys():
    if condition:
        del d[k]

The del[k] line throws the exception. I've added a try/except clause around it and have been able to determine that k in d is False, but k in d.keys() is True.

The keys of d are bound methods of old-style class instances.

The class implements __cmp__ and __hash__, so that's where I've been focusing my attention.

like image 352
Chris AtLee Avatar asked Oct 27 '10 17:10

Chris AtLee


2 Answers

k in d.keys() will test equality iteratively for each key, while k in d uses __hash__, so your __hash__ may be broken (i.e. it returns different hashes for objects that compare equal).

like image 69
adw Avatar answered Oct 04 '22 17:10

adw


Simple example of what's broken, for interest:

>>> count = 0
>>> class BrokenHash(object):
...     def __hash__(self):
...             global count
...             count += 1
...             return count
...
...     def __eq__(self, other):
...             return True
...
>>> foo = BrokenHash()
>>> bar = BrokenHash()
>>> foo is bar
False
>>> foo == bar
True
>>> baz = {bar:1}
>>> foo in baz
False
>>> foo in baz.keys()
True
like image 33
Katriel Avatar answered Oct 04 '22 17:10

Katriel