Skip to main content

How to Create a Dynamic Dictionary in Python

Building dictionaries at runtime is essential for data processing, configuration management, and working with dynamic data structures. Rather than hardcoding key-value pairs, you often need to construct dictionaries programmatically from user input, database results, API responses, or computed values.

This guide walks you through multiple approaches for creating dynamic dictionaries in Python, from merging parallel lists with zip() to grouping data with defaultdict. Each method is explained with clear examples and output so you can choose the right tool for your specific use case.

Using zip() to Merge Parallel Lists

The most common way to build a dictionary from two separate sequences is to combine them with zip() and pass the result to the dict() constructor:

keys = ["id", "name", "email"]
values = [101, "Alice", "alice@example.com"]

user = dict(zip(keys, values))

print(user)

Output:

{'id': 101, 'name': 'Alice', 'email': 'alice@example.com'}

zip() pairs each key with its corresponding value by position, and dict() converts those pairs into a dictionary.

Handling Unequal List Lengths

When the lists have different lengths, zip() silently stops at the shortest one:

keys = ["a", "b", "c", "d"]
values = [1, 2]

result = dict(zip(keys, values))
print(result)

Output:

{'a': 1, 'b': 2}

Keys "c" and "d" are discarded without any warning. This can lead to subtle data loss bugs if you are not expecting it.

Preserving All Keys with zip_longest

Use itertools.zip_longest to include all elements from both lists, filling missing values with a default:

from itertools import zip_longest

keys = ["a", "b", "c", "d"]
values = [1, 2]

result = dict(zip_longest(keys, values, fillvalue=None))
print(result)

Output:

{'a': 1, 'b': 2, 'c': None, 'd': None}

Using Dictionary Comprehension

Dictionary comprehensions let you create dictionaries with transformations, computations, or filtering logic applied inline:

# Squares of numbers
squares = {x: x ** 2 for x in range(6)}
print(squares)

Output:

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

You can add a condition to filter which entries are included:

# Only even numbers
even_squares = {x: x ** 2 for x in range(10) if x % 2 == 0}
print(even_squares)

Output:

{0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

Transforming Existing Data

Dictionary comprehensions are especially useful for converting one data structure into another:

words = ["apple", "banana", "cherry"]

# Map each word to its length
lengths = {word: len(word) for word in words}
print(lengths)

# Map each index to its word
indexed = {i: word for i, word in enumerate(words)}
print(indexed)

Output:

{'apple': 5, 'banana': 6, 'cherry': 6}
{0: 'apple', 1: 'banana', 2: 'cherry'}

Building from Tuples or Key-Value Pairs

The dict() constructor directly accepts any iterable of two-element sequences:

pairs = [("name", "Alice"), ("age", 30), ("city", "Boston")]

user = dict(pairs)
print(user)

Output:

{'name': 'Alice', 'age': 30, 'city': 'Boston'}

This is particularly useful when your data arrives as a list of tuples from a database query, a CSV reader, or a function that yields key-value pairs.

Using fromkeys() for Uniform Default Values

When you need a dictionary with predefined keys that all start with the same value, dict.fromkeys() provides a concise way to create one:

keys = ["read", "write", "execute"]

permissions = dict.fromkeys(keys, False)
print(permissions)

Output:

{'read': False, 'write': False, 'execute': False}

A Common Mistake: Mutable Default Values with fromkeys()

A frequent and confusing bug occurs when you use a mutable object like a list as the default value:

bad = dict.fromkeys(["a", "b"], [])
bad["a"].append(1)
print(bad)

Output:

{'a': [1], 'b': [1]}

Both keys share the same list object, so appending to one affects the other. To give each key its own independent list, use a dictionary comprehension instead:

good = {key: [] for key in ["a", "b"]}
good["a"].append(1)
print(good)

Output:

{'a': [1], 'b': []}
warning

This fromkeys() pitfall applies to any mutable default value, including lists, dictionaries, and sets. Always use a comprehension when each key needs its own independent mutable object.

Using defaultdict for Grouping and Counting

When you are building a dictionary dynamically and do not know the keys in advance, defaultdict from the collections module eliminates the need for key-existence checks:

Counting Occurrences

from collections import defaultdict

items = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counts = defaultdict(int)

for item in items:
counts[item] += 1

print(dict(counts))

Output:

{'apple': 3, 'banana': 2, 'cherry': 1}

When a missing key is accessed, defaultdict(int) automatically initializes it with 0, so += 1 works on the first encounter without raising a KeyError.

Grouping Items by a Property

from collections import defaultdict

users = [
{"name": "Alice", "dept": "Engineering"},
{"name": "Bob", "dept": "Sales"},
{"name": "Carol", "dept": "Engineering"},
{"name": "Dave", "dept": "Sales"}
]

by_department = defaultdict(list)
for user in users:
by_department[user["dept"]].append(user["name"])

print(dict(by_department))

Output:

{'Engineering': ['Alice', 'Carol'], 'Sales': ['Bob', 'Dave']}
note

Each missing key is automatically initialized with an empty list, so you can call .append() directly without checking whether the key exists first.

Using setdefault() for Conditional Initialization

The setdefault() method provides similar functionality to defaultdict but works on regular dictionaries. It sets a key to a default value only if the key does not already exist:

data = {}
items = [("fruits", "apple"), ("vegetables", "carrot"), ("fruits", "banana")]

for category, item in items:
data.setdefault(category, []).append(item)

print(data)

Output:

{'fruits': ['apple', 'banana'], 'vegetables': ['carrot']}

The first time "fruits" is encountered, setdefault creates the key with an empty list. On subsequent encounters, it returns the existing list, and .append() adds the new item to it.

Merging Multiple Dictionaries

When you need to combine dictionaries from different sources, Python offers several approaches depending on your version:

defaults = {"theme": "light", "language": "en"}
user_prefs = {"theme": "dark"}

# Python 3.9+ merge operator
config = defaults | user_prefs
print(config)

Output:

{'theme': 'dark', 'language': 'en'}

For earlier Python versions, use the unpacking syntax:

config = {**defaults, **user_prefs}
print(config)

Output:

{'theme': 'dark', 'language': 'en'}

In both cases, values from the rightmost dictionary take precedence when keys overlap. The "theme" key from user_prefs overrides the one from defaults.

note

The | merge operator creates a new dictionary. If you want to update an existing dictionary in place, use |= or the .update() method:

defaults |= user_prefs       # Python 3.9+
defaults.update(user_prefs) # All Python 3 versions

Method Comparison

MethodSyntaxBest For
dict(zip())dict(zip(keys, values))Merging parallel lists
Comprehension{k: v for k in iterable}Transformations, filtering
dict(pairs)dict([(k1, v1), ...])Converting key-value tuples
fromkeys()dict.fromkeys(keys, val)Uniform immutable defaults
defaultdictdefaultdict(type)Grouping, counting, aggregation
setdefault()d.setdefault(k, default)Conditional initialization
Merge (| or **)d1 | d2 or {**d1, **d2}Combining multiple dictionaries

Conclusion

Python provides a rich set of tools for building dictionaries dynamically.

  • Use dict(zip()) when you have separate sequences of keys and values that need to be paired together. Choose dictionary comprehensions when you need to transform, compute, or filter data during construction.
  • Reach for defaultdict when aggregating data with unknown keys, such as counting occurrences or grouping items. Use setdefault() for conditional initialization on regular dictionaries.
  • And apply merge operators or unpacking when combining multiple dictionaries into one.

By selecting the right method for each situation, you can write cleaner, more efficient, and more Pythonic code for any dynamic dictionary construction task.