Python defaultdict: How to Handle Missing Keys with Examples

| Wednesday, January 1, 2025

Python defaultdict: How to Handle Missing Keys with Examples

Updated June 30, 2026

Master defaultdict and other advanced data structures in our Introduction to Python and Advanced Python courses.

Dictionaries are a convenient way to store data for later retrieval by name (key). Keys must be unique, immutable objects, and are typically strings. The values in a dictionary can be anything. For many applications the values are simple types such as integers and strings.

What is defaultdict in Python?

A defaultdict is a specialized dictionary available in Python's collections module. The collections module extends Python's built-in data structures with specialized container types designed to solve common programming problems. Along with defaultdict, it includes useful tools such as Counter, deque, OrderedDict, and UserDict. 

 It gets more interesting when the values in a dictionary are collections (lists, dicts, etc.) In this case, the value (an empty list or dict) must be initialized the first time a given key is used. While this is relatively easy to do manually, the defaultdict type automates and simplifies such operations. 

 A defaultdict works exactly like a normal dict, but it is initialized with a function (“default factory”) that takes no arguments and provides the default value for a nonexistent key. A defaultdict will never raise a KeyError. Any key that does not exist returns the value from the default factory. 

Under the hood, defaultdict changes how Python handles missing keys. When you access a key using square bracket notation, Python calls the dictionary's __getitem__() method. If the key does not exist, defaultdict calls its __missing__() method, which in turn calls the default factory, stores the returned value in the dictionary, and returns it to your code. A regular dictionary simply raises a KeyError. 

 Developers often compare defaultdict to dict.setdefault(). Both can initialize missing keys, but defaultdict is generally cleaner for repeated access patterns such as counting, grouping, and accumulating values because the initialization happens automatically rather than being written into every operation. 

Setting Custom Default Values With a Lambda

A defaultdict works exactly like a normal dict, but it is initialized with a function (“default factory”) that takes no arguments and provides the default value for a nonexistent key.

A defaultdict will never raise a KeyError. Any key that does not exist gets the value returned by the default factory.

>>> from collections import defaultdict

>>> ice_cream = defaultdict(lambda: 'Vanilla')

>>> 

>>> ice_cream = defaultdict(lambda: 'Vanilla')

>>> ice_cream['Sarah'] = 'Chunky Monkey'

>>> ice_cream['Abdul'] = 'Butter Pecan'

>>> print ice_cream['Sarah']

Chunky Monkey

>>> print ice_cream['Joe']

Vanilla

>>> 

Because "Joe" does not exist in the dictionary, the lambda function is called and returns the default value "Vanilla". A lambda function is a good choice when you need a simple custom default value. For more complex logic, a named function is often easier to read, test, and maintain. When possible, built-in callables such as int, list, and set are often the cleanest option because they clearly communicate the type of default value being created. If your default factory requires arguments, consider using functools.partial to create a callable that satisfies defaultdict's requirement of accepting no arguments. This allows you to preconfigure values while still using them as a default factory.

Be sure to pass the function object to defaultdict(). Do not call the function, i.e. defaultdict(func), not defaultdict(func()).

Counting Occurrences With defaultdict(int)

One of the most common uses of a defaultdict is counting occurrences. In the following example, a defaultdict is used for counting. The default factory is int, which in turn has a default value of zero. (Note: lambda: 0 would also work in this situation.) For each food in the list, the value is incremented by one, where the key is the food. We do not need to make sure the food is already a key—it will use the default value of zero.

>>> from collections import defaultdict

>>> food_list = 'spam spam spam spam spam spam eggs spam'.split()

>>> food_count = defaultdict(int) # default value of int is 0

>>> for food in food_list:

...     food_count[food] += 1 # increment element's value by 1

...

defaultdict(<type 'int'>, {'eggs': 1, 'spam': 7})

>>> 

Because int() returns 0, defaultdict(int) automatically initializes each new key with a starting value of zero. This eliminates the need to check whether a key already exists before incrementing its value. Counting is a common pattern in frequency analysis, log processing, inventory tracking, survey reporting, and other applications where you need to track how often a value appears in a dataset. 

defaultdict(int) vs Counter

If your primary goal is counting occurrences, Python's collections. Counter is often the most purpose-built solution. •

  • Use Counter for straightforward counting tasks.
  • Use defaultdict(int) when counting is part of a larger workflow that also requires custom processing, grouping, or additional logic. 

Both approaches are useful, but Counter is designed specifically for frequency counting, while defaultdict(int) provides more flexibility when building custom data structures.

Other Numeric Default Factories 

 The default factory does not have to be int. Other numeric types can be useful depending on the problem you're solving. 

 For example, defaultdict(float) is commonly used when accumulating totals, averages, percentages, or financial values. In the same way that defaultdict(int) starts each key at 0, defaultdict(float) starts each key at 0.0.  

Grouping Items With defaultdict(list)

In the next example, we start with a list of states and cities. We want to build a dictionary where the keys are the state abbreviations and the values are lists of all cities for that state. To build this dictionary of lists, we use a defaultdict with a default factory of list. A new list is created for each new key.

>>> from collections import defaultdict

>>> city_list = [('TX','Austin'), ('TX','Houston'), ('NY','Albany'), ('NY', 'Syracuse'), ('NY', 'Buffalo'), ('NY', 'Rochester'), ('TX', 'Dallas'), ('CA','Sacramento'), ('CA', 'Palo Alto'), ('GA', 'Atlanta')]

>>> 

>>> cities_by_state = defaultdict(list)

>>> for state, city in city_list:

...     cities_by_state[state].append(city)

...

for state, cities in cities_by_state.iteritems():

...     print state, ', '.join(cities)

...

NY Albany, Syracuse, Buffalo, Rochester

CA Sacramento, Palo Alto

GA Atlanta

TX Austin, Houston, Dallas

Use defaultdict(list) when duplicate values should be preserved. Use defaultdict(set) when each grouped value should appear only once.

When to Reach for defaultdict (and How to Go Deeper) 

 As a rule, use defaultdict whenever each new key should start with a predictable default value. It helps reduce boilerplate code, eliminates many KeyError exceptions, and makes common patterns such as counting, grouping, and accumulating values easier to read and maintain. A simple decision guide:

  • Counting occurrences → Use collections.Counter
  • Grouping related values → Use defaultdict(list)
  • Grouping unique values → Use defaultdict(set)
  • Accumulating totals → Use defaultdict(int) or defaultdict(float)
  • Handling missing keys automatically → Use defaultdict 

While defaultdict is one of the most useful tools in Python's collections module, it's only one member of a larger family of specialized data structures. As you continue building your Python skills, it's worth exploring related classes such as Counter for counting hashable objects, deque for efficient queue and stack operations, OrderedDict for ordered mappings, and UserDict for creating custom dictionary behavior. In short, whenever you need a dictionary, and each element's value should start with a default value, use a defaultdict. 

 Ready to build practical Python skills beyond the basics? Ascendient Learning offers instructor-led Python training for individuals and teams, including vendor-authorized courses, hands-on labs, and live expert instruction. 

Whether you're learning Python fundamentals or expanding into advanced topics such as data structures, automation, and application development, our courses provide the real-world experience needed to apply new skills immediately. 

 

In conclusion, whenever you need a dictionary, and each element’s value should start with a default value, use a defaultdict.

Browse our Python Training courses. Ascendient Learning offers courses for teams and individual and all training is hands-on and live.

 

Git and GitHub: Their Uses and Differences

Git and GitHub: Their Uses and Differences

Git and GitHub are reliably proven development tools supported by a global online community where users can find how-to and troubleshooting tips. See how they stack up against each other in our blog.

Development