Skip to content

How to Create a Dynamic Dictionary in Python

Learn how to build Python dictionaries at runtime using zip(), comprehensions, defaultdict, setdefault(), and merging techniques for data processing, API responses, and configuration management.

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.

Using Dictionary Comprehension

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

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:

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"]

lengths = {word: len(word) for word in words}
print(lengths)

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': []}

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']}

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"}

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.

Method Comparison

Method Syntax Best 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
defaultdict defaultdict(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.

Navigation