When working with dictionaries in Python, or any equivalent data structure in some other language, it is quite important to remember the difference between a key which is not present and a key that maps to
null) value. We often tend to blur the distinction by using
We do that because more often that not,
None and other falsy values (such as empty strings) are not interesting on their own, so we may as well lump them together with the “no value at all” case.
There are some situations, however, where these variants shall be treated separately. One of them is building a dictionary of keyword arguments that are subsequently ‘unpacked’ through the
**kwargs construct. Consider, for example, this code:
With a key mapping to
None, we’re calling the function with argument explicitly set to
None. Without the key present, we’re not passing the argument at all, allowing it to assume its default value.
But adding or not adding a key to dictionary is somewhat more cumbersome than mapping it to some value or
None. The latter can be done with conditional expression (
x if cond else None), together with many other keys and value at once. The former requires an
if statement, as shown above.
Would it be convenient if we had a special “
missing” value that could be used like
None, but caused the key to not be added to dictionary at all? If we had it, we could (for example) rewrite parts of the previous function that currently contain
It shouldn’t be surprising that we could totally introduce such a value and extend
dict to support this functionality – after all, it’s Python we’re talking about :) Patching the
dict class itself is of course impossible, but we can inherit it and come up with something like the following piece:
missing object is only a marker here, used to filter out keys that we want to ignore.
With this class at hand, some dictionary manipulations become a bit shorter:
We could take this idea further and add support for
missing not only initialization, but also other dictionary operations – most notably the
__setitem__ assignments. This gist shows how it could be done.
Python dictionaries have an inconspicuous method named
setdefault. Asking for its description, we’ll be presented with rather terse interpretation:
While it might not be immediately obvious what we could use this method for, we can actually find quite a lot of applications if we only pay a little attention. The main advantage of
setdefault seems to lie in elimination of
ifs; a feat we can feel quite smug about. As an example, consider a function which groups list of key-value pairs (with possible duplicate keys) into a dictionary of lists:
This is something which we could do when parsing query string of an URL, if there weren’t a readily available API for that:
setdefault we can get the same job done more succinctly. It would seem that it is a nifty little function, and something we should keep in mind as part of our toolbox. Let’s remember it and move on, shall we?…
setdefault is really not a good piece of
dict‘s interface, and the main reason we should remember about it is mostly for its caveats. Indeed, there are quite a few of them, enough to shrink the space of possible applications to rather tiny size. As a result, we should be cautious whenever we see (or write)
setdefault in our own code.