Adding an Entry to a Dictionary

Credit: Alex Martelli

Problem

Working with a dictionary D, you need to use the entry D[k] if it’s already present, or add a new D[k] if k isn’t yet a key in D.

Solution

This is what the setdefault method of dictionary objects is for. Say we’re building a word-to-page numbers index. A key piece of code might be:

theIndex = {}
def addword(word, pagenumber):
    if theIndex.has_key(word):
        theIndex[word].append(pagenumber)
    else:
        theIndex[word] = [pagenumber]

Good Pythonic instincts suggest substituting this “look before you leap” pattern with an “easier to get permission” pattern (see Recipe 5.4 for a detailed discussion of these phrases):

def addword(word, pagenumber):
    try: theIndex[word].append(pagenumber)
    except KeyError: theIndex[word] = [pagenumber]

This is just a minor simplification, but it satisfies the pattern of “use the entry if it is already present; otherwise, add a new entry.” Here’s how using setdefault simplifies this further:

def addword(word, pagenumber):
    theIndex.setdefault(word, []).append(pagenumber)

Discussion

The setdefault method of a dictionary is a handy shortcut for this task that is especially useful when the new entry you want to add is mutable. Basically, dict.setdefault(k, v) is much like dict.get(k, v), except that if k is not a key in the dictionary, the setdefault method assigns dict[k]=v as a side effect, in addition to returning v. (get would just return v, without affecting dict in any way.) Therefore, setdefault is appropriate any time you have get-like needs but also want to produce this specific side effect on the dictionary.

setdefault is particularly useful in a dictionary with values that are lists, as detailed in Recipe 1.6. The single most typical usage form for setdefault is:

somedict.setdefault(somekey, []).append(somevalue)

Note that setdefault is normally not very useful if the values are immutable. If you just want to count words, for example, something like the following is no use:

theIndex.setdefault(word, 1)

In this case, you want:

theIndex[word] = 1 + theIndex.get(word, 0)

since you will be rebinding the dictionary entry at theIndex[word] anyway (because numbers are immutable).

See Also

Recipe 5.4; the Library Reference section on mapping types.

Get Python Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.