[Python-Dev] Creating dicts from dict subclasses (original) (raw)

Walter Dörwald walter at livinglogic.de
Thu Dec 14 14:11:38 CET 2006


Guido van Rossum wrote:

On 12/13/06, Walter Dörwald <walter at livinglogic.de> wrote:

Guido van Rossum wrote: > On 12/13/06, Walter Dörwald <walter at livinglogic.de> wrote: >> I tried to reimplement weakref.WeakValueDictionary as a subclass of >> dict. The test passes except for one problem: To compare results >> testweakref.py converts a weakdict to a real dict via dict(weakdict). >> This no longer works because PyDictMerge() does a PyDictCheck() on the >> argument and then ignores all overwritten methods. (The old version >> worked because UserDict.UserDict was used). >> >> The simplest solution is to replace the PyDictCheck() call with >> PyDictCheckExact(), but this might slow things down too much, because >> the fallback code basically does: >> >> for key in iter(arg.keys()): >> self[key] = arg.getitem(key) >> >> Why can't we use: >> >> for key in iter(arg): >> self[key] = arg.getitem(key) >> >> instead? > > The only reason I can think of is backwards compatibility: not all > "mappings" created pre-2.2 would support iteration. Maybe you could > check for a tpiter slot and if non-NULL use the latter otherwise use > the original fallback?

This doesn't seem to work. It breaks testupdate() in testdict.py which does this: d = {} class SimpleUserDict: def init(self): self.d = {1:1, 2:2, 3:3} def keys(self): return self.d.keys() def getitem(self, i): return self.d[i] d.update(SimpleUserDict()) self.assertEqual(d, {1:1, 2:2, 3:3}) This fails with KeyError: 0 because SimpleUserDict doesn't implement iter, so it gets an iterator implementation via getitem. So maybe this only makes sense for Python 3.0 where we can demand that dict-like classes implement iter? Ah, right. But I think you should still use PyDictCheckExact, and slow fallbacks be damned. (I guess you could look for iterkeys first.)

OK, here's a patch that tries iterkeys() before keys(): http://bugs.python.org/1615701

Both versions seem to be faster than Python 2.5:

class dictik: def init(self, n): self.d = dict((i, i) for i in xrange(n)) def iterkeys(self): return iter(self.d) def getitem(self, i): return self.d[i]

class dictk: def init(self, n): self.d = dict((i, i) for i in xrange(n)) def keys(self): return self.d.keys() def getitem(self, i): return self.d[i]

$ python2.5 -mtimeit -s'from foo import dictik, dictk; d=dictk(100000)' 'dict(d)' 10 loops, best of 3: 179 msec per loop $ ./python -mtimeit -s'from foo import dictik, dictk; d=dictk(100000)' 'dict(d)' 10 loops, best of 3: 138 msec per loop $ ./python -mtimeit -s'from foo import dictik, dictk; d=dictik(100000)' 'dict(d)' 10 loops, best of 3: 123 msec per loop

Servus, Walter



More information about the Python-Dev mailing list