weird dict problem, how can this even happen?

Joel Hedlund joel.hedlund at gmail.com
Tue Dec 16 09:36:38 CET 2008


Duncan Booth wrote:
> It could happen quite easily if the hash value of the object has changed 
> since it was put in the dictionary. what does the definition of your 
> core.gui.FragmentInfo object look like?

Dunno if it'll help much, but:

class FragmentInfo(object):
     def __init__(self, renderer, render_area):
         self.renderer = renderer
         self.render_area = render_area

     def __hash__(self):
         return hash((FragmentInfo, self.renderer, self.render_area))

     def __eq__(self, other):
         return (isinstance(other, self.__class__) and
                 other.renderer == self.renderer and
                 other.render_area == self.render_area)

> Is the hash definitely immutable?

No. It's a hash of a tuple of its key attributes, themselves similar 
objects.

The program can be thought of as a map viewer. In the gui part, image 
fragments are cached for speed, and fragments are only half rendered if 
there's a lot of complex features to draw. The "pool" consists of semi 
rendered fragments. The reason I did it this way is the cache. The cache 
is a dict with a use tracker so when the hash changes, the older 
fragments eventually drop from the cache. Hmm... I'm starting to realise 
now why my implementation of this isn't so hot. I'm going to hazard a 
guess here, and then you can correct me ok?

I create a dict and populate it with a key-value pair, and then the 
key's hash changes. When the key is returned by k = d.keys(), then k not 
in d, even though k in d.keys().

Simple example:
> class moo(object):
>     def __init__(self, a):
>         self.a = a
>     def __hash__(self):
>         return hash(self.a)
> 
> d = {moo(1): 1}
> 
> k = d.keys()[0]
> k.a = 2
> 
> k = d.keys()[0]
> print k in d, k in d.keys()
 > d.pop(k)

output:
> False True
> Traceback (most recent call last):
>   File "/bioinfo/yohell/eclipse/Test/src/test.py", line 14, in <module>
>     d.pop(k)
> KeyError: <__main__.moo object at 0x7f1c64120590>

I'd say that's pretty similar to what I observed.

I guess the logical outcome is that the cache dict will fill up with old 
junk that I can't access and can't selectively flush since the hashes 
have changed, unless I actually somehow save copies of the keys, which 
can get pretty complex and probably won't do wonders for execution 
speed. Yeah this was probably a bad soulution.

I should probably do this with lists instead because I can't really 
think of a way of salvaging this. Am i right?

Thanks for your help!
/Joel



More information about the Python-list mailing list