In this tutorial, you’ll learn how to use defaultdict from Python’s collections module—to handle KeyErrors better—when working with Python dictionaries.

In Python, a dictionary is a powerful built-in data structure that stores data in key-value pairs. You’ll use the keys to tap into the dictionary and access the values. 

However, when you have multiple dictionaries in your Python script that are modified during code execution, you’ll often run into KeyErrors. And there are a few different ways you can handle them. 

In this tutorial, you will learn:

  • What KeyErrors are and why they arise 
  • How to handle KeyErrors
  • How to use Python’s defaultdict, a subclass that inherits from the built-in dict class, to handle missing keys better 

Let’s begin!

What Are KeyErrors in Python?

1

When defining a Python dictionary, you should take care to you should ensure the following:

  • The keys should be unique – without any repetition. 
  • When using an existing iterable as the keys of a dictionary, you should prefer using an immutable collection such as a tuple.

So a key is valid only if it is present in the dictionary; else it leads to KeyErrors.

Consider the following dictionary, books_authors, in which the keys are the names of the books and the values are the names of the authors.

You can code along with this tutorial in a Python REPL.

books_authors = {
    'Deep Work':'Cal Newport',
    'Hyperfocus':'Chris Bailey',
    'Pivot':'Jenny Blake',
    'The Happiness Equation':'Neil Pasricha'
}

You can use the key (name of the book) to access the author’s name.

books_authors['Hyperfocus']
'Chris Bailey'

To access all the key-value pairs in the dictionary, you can call the items() method on the dictionary object, as shown below:

for book,author in books_authors.items():
  print(f"'{book}' by {author}")
'Deep Work' by Cal Newport
'Hyperfocus' by Chris Bailey
'Pivot' by Jenny Blake
'The Happiness Equation' by Neil Pasricha

If you try to access the value of a key that is not present in the dictionary, the Python interpreter raises a KeyError. We run into KeyError when we try to access the value of keys that do not exist, namely, ‘Grit’ and ‘non-existent key’.

books_authors['Grit']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-e1a4486f5ced> in <module>
----> 1 books_authors['Grit']

KeyError: 'Grit'
books_authors['non-existent-key']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-7-a3efd56f69e5> in <module>
----> 1 books_authors['non-existent-key']

KeyError: 'non-existent-key'

So how do you handle KeyErrors in Python?

There are few ways to do it, and we’ll learn them in the next section.

How to Handle KeyErrors in Python

How-to-Handle-KeyErrors-in-Python

Let’s learn how to handle KeyErrors using:

  • If-else  conditional statements 
  • Try-except blocks 
  • The dictionary method .get()

#1. Using If-Else Conditional Statements

One of the most simple ways to handle KeyErrors in Python is using the if-else conditional statements.

In Python, if-else statements have the following general syntax:

 if condition:
 	# do this 
 else:
    # do something else 
  • If the condition is True, the statements in the if body get executed, and 
  • If the condition is False, the statements in the else body is executed.

In this example, the condition is to check if the key is present in the dictionary.

If the key is present in the dictionary, the in operator will return True, and if body will be executed printing out the corresponding value.

key = 'The Happiness Equation'
if key in books_authors:
  print(books_authors[key])
else:
  print('Sorry, this key does not exist!')

# Output
# Neil Pasricha

If the key is not present in the dictionary, the in operator returns False and the else body will be executed. It prints out a message that the key is not present.

key = 'non-existent-key'
if key in books_authors:
  print(books_authors[key])
else:
  print('Sorry, this key does not exist!')

# Output
# Sorry, this key does not exist!

#2. Using Try-Except Statements

2

Another common method to handle KeyError is using the try-except statements in Python.

Read through the following code block:

key = 'non-existent-key'
try:
  print(books_authors[key])
except KeyError:
  print('Sorry, this key does not exist!')
  • The try block tries to retrieve the value corresponding to the key provided.
  • If the key is not present, the interpreter raises a KeyError which is handled as an exception within the except block.

#3. Using the .get() Method

In Python, you can use the built-in dictionary method .get() to handle missing keys.

The general syntax to use the get() method is dict.get(key,default_value) where dict is a valid dictionary object in Python. 

– If the key is present in the dictionary, then the get() method returns the value.
– Else, it returns the default value.

In this example, keys is a list of keys whose values we would like to access. We loop through the keys list to retrieve the corresponding values from the books_authors dictionary.

Here, we’ve used the .get() method with ‘Does not exist’ as the default value.

keys = ['Grit','Hyperfocus','Make Time','Deep Work']
for key in keys:
  print(books_authors.get(key,'Does not exist'))

In the above code:

  • For keys that are present in the books_authors dictionary, the .get() method returns the corresponding values.
  • When the keys do not exist, in this case, ‘Grit’ and ‘Make Time’, the .get() method returns the default value ‘Does not exist’.
# Output

Does not exist
Chris Bailey
Does not exist
Cal Newport

All the above methods help us in handling key errors. However, they are verbose and require us to explicitly handle the missing keys. You can simplify this process by using a  defaultdict instead of a regular dictionary.

Defaultdict in Python

python-defaultdict

The defaultdict is a subclass of the dictionary (dict) class. So it inherits the behavior of a Python dictionary. In addition, it also handles missing keys natively.

The defaultdict is a container data type that is built into the Python standard library – inside of the collections module.

So you’ve to import it into your working environment:

from collections import defaultdict

Here’s the general syntax to use defaultdict:

defaultdict(default_factory)

You can specify a callable such as int, float, or list as the default_factory attribute. If you don’t provide a value for the default_factory, it defaults to None.

When the key you’re looking for is not present, the __missing__() method is triggered, and it infers the default value from the default_factory. It then returns this default value.

In summary:

  • In Python, a defaultdict returns the default value when the key is not present.
  • It also adds this key-default value pair to the dictionary, which you can then modify.

Python Defaultdict Examples

Defaultdict-Examples-1

Next, we’ll code a few examples to understand how Python defaultdict works.

Defaultdict in Python with Default Integer Value

First, import defaultdict from the collections module.

from collections import defaultdict
import random

Let us create a defaultdict prices.

prices = defaultdict(int)

We now populate the prices dictionary using the items of the fruits list as the keys. And we randomly sample values from the price_list to get the values.

price_list = [10,23,12,19,5]
fruits = ['apple','strawberry','pomegranate','blueberry']

for fruit in fruits:
  prices[fruit] = random.choice(price_list)

Let’s take a look at the key-value pairs in the prices defaultdict.

print(prices.items())
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10)])

Like a regular Python dictionary, you can access the values of the prices defaultdict using the keys:

prices['apple']
# 23

Now, let’s try to access the price of a fruit that is not present, say, ‘orange’. We see that it returns the default value of zero.

prices['orange']
# 0

If we print out the dictionary, we see that a new key ‘orange’ has been added with the default integer value of zero.

print(prices.items())
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10), ('orange', 0)])

Defaultdict in Python with List as the Default Value

Let’s define students_majors as a defaultdict of lists. The names of the majors are the keys. And the values are the lists of students pursuing each of the majors, such as math, economics, computer science, and more.

from collections import defaultdict
students_majors = defaultdict(list)

If we try to access the student list corresponding to ‘Economics’, defaultdict returns an empty list; no key errors!

students_majors['Economics']
# []

We now have an empty list mapped to the ‘Economics’ major. So we can now add elements to this list using the list method .append().

students_majors['Economics'].append('Alex')

An entry has been created for ‘Economics’ in the students_majors default dictionary.

print(students_majors)
defaultdict(<class 'list'>, {'Economics': ['Alex']})

You can add more students to the list mapping to the Economics major, add a new major, and much more!

students_majors['Economics'].append('Bob')
students_majors['Math'].append('Laura')
print(students_majors)
defaultdict(<class 'list'>, {'Economics': ['Alex', 'Bob'], 'Math': ['Laura']})

Conclusion

I hope this tutorial helped you understand how and when you should use defaultdict in Python. After running the code examples in this tutorial, you can try using defaultdict as the preferred data structure in your projects when needed.

Here is a summary of what you’ve learned in this tutorial.

  • When working with a Python dictionary, you’ll often run into KeyErrors.
  • To handle such KeyErrors you can use a few verbose methods. You can use conditional statements, try-except blocks, or the .get() method. But the defaultdict data type in the collections module can simplify this KeyError handling.
  • You can use defaultdict(default_factory) where default_factory is a valid callable.
  • When the key is not present in the defaultdict, the default value (inferred from default_factory) and the key is added to the defaultdict.

Next, check out the tutorial on Python map function.