DEV Community

Cover image for defaultdicts: Never Check If a Key is Present Again!

defaultdicts: Never Check If a Key is Present Again!

Ryan Palo on November 18, 2018

Cover image by Romain Vignes on Unsplash. It's fall, so it seems like the perfect time to write some posts about PSL. Nope, not Pumpkin Spice Lat...
Collapse
 
karolyi profile image
László Károlyi

I know dicts are ordered by default from 3.7 onwards (so you could just use defaultdict), but I needed to mix the defaultdict and OrderedDict at one point. Introducing the DefaultOrderedDict:

from collections import OrderedDict
from copy import deepcopy


class DefaultOrderedDict(OrderedDict):
    """Extending getter functions to provide defaults."""
    _default = dict()

    def __init__(self, *args, default, **kwargs):
        self._default = default
        super().__init__(*args, **kwargs)

    def __getitem__(self, key):
        if key in self:
            return self.get(key)
        value = self[key] = deepcopy(self._default)
        return value

    def __deepcopy__(self, memo):
        """Return a deep copy of self."""
        obj = DefaultOrderedDict(default=self._default)
        for key, value in self.items():
            obj[key] = deepcopy(value)
        return obj

one example of how it can be used:

terms_by_func = DefaultOrderedDict(default=[])

it will basically deepcopy() the contents of the default value.

Collapse
 
rpalo profile image
Ryan Palo

Neat! My first thought was to wonder if it could be done with multiple inheritance between defaultdict and OrderedDict, but that seems like that could be a big nightmare, so your method is probably cleaner. :)

Collapse
 
vdedodev profile image
Vincent Dedo • Edited

If you're covering collections, why not also give a quick mention to Counter?

from collections import Counter

grades = ["A", "A", "B", "C", "D", "C", "B", "C", "A", "C", "B"]

counter = Counter(grades)
# counter dict is {"A": 3, "B": 3, "C": 4, "D": 1}
Collapse
 
rpalo profile image
Ryan Palo • Edited

You're right! I wanted to dedicate another article to Counter. There's too much goodness for just a quick blurb :)

(From the article:)

There's a lot more goodies in there (not least of which is the actual Counter class which takes care of our very problem here. But, again, that's for another PSL article).

Collapse
 
vdedodev profile image
Vincent Dedo

Nice one, that's what I get for skimming the article and rushing to reply.

Collapse
 
rhymes profile image
rhymes • Edited

Love this idea of uncovering gems in the standard library :-)

Maybe I'll do one as well :)

Something like pymotw3 but about a single feature, not an entire module

Collapse
 
rpalo profile image
Ryan Palo

Yeah I’ve got a few favorites that I’ve got planned 😁 you should definitely do one!

Collapse
 
rhymes profile image
rhymes

I already have one or two in mind :D I'll write about them soon