a clean way to define dictionary

Michele Simionato mis6 at pitt.edu
Thu Jun 19 23:32:19 CEST 2003

Alexander Schmolck <a.schmolck at gmx.net> wrote in message news:<yfswufi6j86.fsf at black132.ex.ac.uk>...
> mis6 at pitt.edu (Michele Simionato) writes:
> Well, your timings are not all that meaningful because your code does nothing
> and you only instance creation and not item access (which obviously also needs
> to be overridden with python code). 

This was on purpose, I wanted to measure the slowdown due to "pure" 
subclassing, i.e. without doing anything to __getattr__ and __setattr__.

> Anywhere, here is a real DefaultDict class
> and some ad hoc timings, which show *10* fold slowdown for creation and 4 fold
> for item access (the copy.copy call seems harmless performance-wise).
> class DefaultDict(dict):
>     r"""Dictionary with a default value for unknown keys."""
>     def __init__(self, default, noCopies=False):
>         self.default = default
>         if noCopies:
>             self.noCopies = True
>         else:
>             self.noCopies = False
>     def __getitem__(self, key):
>         r"""If `self.noCopies` is `False` (default), a **copy** of
>            `self.default` is returned by default.
>         """              
>         if key in self: return self.get(key)
>         if self.noCopies: return self.setdefault(key, self.default)
>         else:             return self.setdefault(key, copy.copy(self.default))
> timings for python2.2
> In [58]: timeCall(nTimes, 10000, dict)
> Out[58]: 0.018522977828979492
> In [59]: timeCall(nTimes, 10000, DefaultDict, 1)
> Out[59]: 0.11231005191802979
> In [47]: timeCall(nTimes, 10000, {'foo':0}.__getitem__, 'foo')
> Out[47]: 0.012811064720153809
> In [48]: timeCall(nTimes, 10000, DefaultDict(1).__getitem__, 'foo')
> Out[48]: 0.045480012893676758
> In [65]: timeCall(nTimes, 10000, DefaultDict(1,0).__getitem__, 'foo')
> Out[65]: 0.04657900333404541
> What are your results for instance creation with this class? Maybe 2.3 is
> noticeably faster?
> 'as

I should perform a series of tests; anyway, some simple experiment 
with attribute access gives me a slowdown of ~14 times. Quite a lot.
However, my point was that you can bypass the Python 2.3 change in the 
dictionary constructor signature by overriding __new__ and *not* changing
__getattr__. In this way, you don't have a performance problem.
Of course, if you override __getattr__, there is an issue, but the
issue would be the same with Python 2.2. 
I am curious to test the difference between Python 2.2 and 2.3; 
I will look at the instance creation time too, but this is less
important than the access time, since typically I create a dictionary 
only once.


More information about the Python-list mailing list