Python for Programmers: Defaultdict
Welcome to the Defaultdict lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
Suppose that we want to count how many times each word appears in a string. We might build a dictionary where the keys are words and the values are word counts.
>
def word_count(s):counts = {}for word in s.split(" "):if word not in counts:counts[word] = 0counts[word] += 1return counts- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
word_count("a cat is a cat")Result:
Dicts raise
KeyErrorwhen we access keys that don't exist. That's why our code had to checkif word not in counts.>
counts = {}counts["cat"]Result:
KeyError: 'cat'
With Python's
defaultdict, we can skip theif word not in countscheck. It's a dictionary-like object that takes a default value function. When we access a key that doesn't exist, thedefaultdictcalls the function and gives us its return value.>
from collections import defaultdictcounts = defaultdict(lambda: 0)counts["a key that doesn't exist"]Result:
0
With
defaultdict, we can simplify our originalword_countfunction.Here's a code problem:
The
word_countfunction below has a bug: it tries to modify dict keys that don't exist, which raises an exception. Fix the function by using adefaultdictinstead of a regulardict. The default value should be 0.(Only one line of code is editable. You don't need to change any other lines!)
from collections import defaultdictdef word_count(s):counts = defaultdict(lambda: 0)for word in s.split(" "):counts[word] += 1return counts# We convert back to a dict for printing, since it's more readable.dict(word_count("a cat is a cat"))- Goal:
{'a': 2, 'cat': 2, 'is': 1}- Yours:
{'a': 2, 'cat': 2, 'is': 1}
After we access a key that doesn't exist, does that key now exist in the
defaultdict? Or does it return the default value to us without actually adding the key to the dictionary? We can write some code to check.>
from collections import defaultdictcounts = defaultdict(lambda: 0)counts["some key"]"some key" in countsResult:
Merely reading a
defaultdictkey ensures that it exists, even if we never write to that key.You might wonder why we provide the default value in the form of a function, like
defaultdict(lambda: 0), rather than directly providing the value, likedefaultdict(0).One important reason is that we might want the default value to change over time. For example, imagine that we're tracking integer ID numbers for users. When we try to get a user's ID for the first time, we want to assign them a new, unique ID. Then, we should always get that same ID for that user.
>
from collections import defaultdictnext_id = 1def get_next_id():global next_idid = next_idnext_id += 1return iduser_ids = defaultdict(get_next_id)first_amir_id = user_ids["Amir"]betty_id = user_ids["Betty"]second_amir_id = user_ids["Amir"](first_amir_id, betty_id, second_amir_id)Result:
(1, 2, 1)
That code is already pretty terse. However, in a future lesson we'll see a way to make it much shorter!