In my previous post I introduced FileDict. I did my best to get it right the first time, but as we all know, this is impossible for any non-trivial piece of code.
I want to thank everyone for their comments and remarks. It’s been very helpful.
The Unreliable Pickle
A special thanks goes to the mysterious commenter “R”, for pointing out that pickling identical objects may produce different strings (!), which are therefor inadequate to be used as keys. And my FileDict indeed suffered from this bug, as this example shows:
>>> key = (1, u'foo') >>> d[(1, u'foo')] = 4 >>> d[(1, u'foo')] 4 >>> d[key] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "filedict.py", line 64, in __getitem__ raise KeyError(key) KeyError: (1, u'foo')
And if that’s not bad enough:
>>> d[key] = 5 >>> list(d.items()) [['a', 3], [(1, 2), 3], [(1, u'foo'), 4], [(1, u'foo'), 5]]
Ouch.
I’ve rewritten the entire storing mechanism to poll only on hash and compare keys after unpickling. This may be a bit slower, but I don’t (and shouldn’t) expect many colliding hashes anyway.
Bug is fixed.
DictMixin
Under popular demand, I’m now inheriting from DictMixin. It’s made my code a bit shorter, and was not at all painful.
Copy and Close
I no longer close the database on __del__, and instead I rely on the garbage collector. It seems to close the database on time, and it allows to one copy the dictionary (which, of course, will all be always have the same keys, but doesn’t have to have the same behavior or attributes).
New Source Code
Is available here