Some Dict Patterns August 10, 2011
Posted by PythonGuy in Advanced Python, Python.trackback
Introduction
I have seen a lot of Python code, as well as Java, Perl, and other languages. When dealing with dicts, I have identified a few patterns that I feel are optimal, depending on the situation. These are extraordinarily simple.
NOTE: The dict data structure is known by many names: map, a hashmap, an associative array, a hash, or even a table.
Use if Present
For instance, how many times have you written the following pseudo-code in your language of choice?
# pseudo-code
if key is in map:
lookup value in map with key
use value
Python provides the “get()” method which returns None if it is not present.
# Python
value = map.get(key)
if value is not None:
# use value
Of course, sometimes you need to distinguish between values that are None and that are not present in the dict. You can rely on exceptional behavior for this:
# Python
try:
value = map[key]
except KeyError:
pass
else:
# use value
Or you can use the “in” test:
# Python
if key in map:
value = map[key]
# use value
The above, of course, does 2 dict lookups.
Exceptions versus Lookups
There is discussion about whether to use exceptions or lookups. The general rule of thumb is that exceptions are not as slow as you think, since Python is pretty slow to begin with. “Slow”, of course, is a relative term that is meaningful when you compare Python to C/C++. And nowadays with PyPy, “slow” isn’t a proper word for it anymore.
Use Value or Default If Missing
Sometimes you want to use a default value if the key is not present. This is simply:
# Python value = map.get(key, 'default')
Note that whatever expression you use as the default value will be evaluated, whether or not it was used. If the expression is expensive to calculate, then you can use this form:
# Python
value = map.get(key)
if value is None:
value = expensive_expression()
Notice that you’re back to the previous pattern if you need to distinguish between a value of None and a missing key.
Use Value or Default and Store if Missing
Sometimes you want to store the default value in the dict if it is missing. “setdefault()” is the ideal method for this.
# Python value = map.setdefault(key, 'default')
Of course, the caveats for expensive default expressions applies.
Conclusion and Summary
Those of you who are unfamiliar with Python might note how similar all of the above patterns are. Indeed, if you simply learn what the following expressions mean, you don’t have to think very hard to understand what the code does or to choose the right code:
- key in dict
- dict[key]
- dict.get(key)
- dict.get(key, default)
- dict.setdefault(key, default)
Nice thorough treatment; I was just looking into this today and found lots of snippets around the Net, but yours collects quite a bit together at once.
Would you care to add commentary on collections.defaultdict? I realize it’s not a pure dict, but it’s That is what I ended up using in my code, where I’m explicitly updating a dict with “blah['key'] += value”. This is in place of “blah['key'] = blah.get(‘key’, 0) + value”. I just like how the former cleanly reads like my thought process.
Oops… “not a pure dict, but it’s in the standard library.”
defaultdict is good only when you want the default values for all the keys to be the same. I haven’t found a common use for this, except perhaps configuration dicts.
Agreed. The one limited use in my case is a slew of counters, indexed by name. Counters will all begin at zero and are all ints. I suppose you could call those measurement dicts?
For me, the primary gain is syntactic; I can do += as above, or with lists, I can append without having to initialize an empty list for the one-time case of a non-existent key.
Cheers
That’s a good case.
I prefer to use an if with dict.has_key(key), which I find more readable.