Python
dictionary
programming
coding
tutorial

Creating a new dictionary in Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Creating a dictionary is one of the first things Python developers learn because dictionaries are used everywhere, from configuration data to fast lookups and counters. Python gives you several ways to build one, and the best choice depends on whether your keys are known in advance, generated dynamically, or coming from existing data.

Start with Literal Syntax

If you already know the keys and values, dictionary literal syntax is usually the clearest option.

python
1user = {
2    "id": 101,
3    "name": "Ava",
4    "active": True,
5}
6
7print(user["name"])

This style is readable and direct. It is the default choice for static mappings written by hand.

Use dict() When the Input Shape Fits It

The dict constructor is useful in two common cases. The first is keyword-style creation:

python
config = dict(timeout=30, retries=3, debug=False)
print(config)

This is compact, but it works only when the keys are valid Python identifiers. For keys such as "max-retries" or "user name", use literal syntax or iterable conversion instead.

The second common use is converting key-value pairs into a dictionary:

python
pairs = [("us", "United States"), ("ca", "Canada"), ("mx", "Mexico")]
countries = dict(pairs)
print(countries)

This is handy when data already exists as tuples, zipped columns, or parsed records.

Dictionary Comprehensions for Generated Data

When keys and values are derived from a pattern, a dictionary comprehension is often the cleanest solution.

python
1squares = {n: n * n for n in range(6)}
2print(squares)
3
4evens = {n: n for n in range(10) if n % 2 == 0}
5print(evens)

Comprehensions are concise, but do not force complicated logic into one line just because you can. If the expression becomes hard to read, a regular loop is better.

Build Incrementally in a Loop

For multi-step logic, create an empty dictionary and fill it as you go.

python
1counts = {}
2
3for word in ["apple", "banana", "apple", "kiwi"]:
4    counts[word] = counts.get(word, 0) + 1
5
6print(counts)

This pattern is extremely common because it stays readable even when the update logic becomes more complex than a simple comprehension can handle.

fromkeys() and Shared Defaults

dict.fromkeys() creates a dictionary with the same default value for every key.

python
statuses = dict.fromkeys(["queued", "running", "done"], 0)
print(statuses)

That is fine for immutable defaults such as numbers or strings. With mutable defaults, however, every key shares the same underlying object.

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

Both keys now point to the same list. That surprises people constantly, so avoid fromkeys with mutable defaults unless shared state is exactly what you want.

Nested Dictionaries and Practical Patterns

Real-world data is often nested, and dictionaries make that natural:

python
1orders = {
2    "ORD-1": {
3        "customer": "Liam",
4        "items": 3,
5    }
6}
7
8print(orders["ORD-1"]["customer"])

If you need to build nested mappings dynamically, defaultdict can reduce boilerplate:

python
1from collections import defaultdict
2
3index = defaultdict(dict)
4index["users"][101] = "Ava"
5print(index["users"][101])

That can be more convenient than repeatedly checking whether intermediate keys already exist.

Copying and Merging Dictionaries

Creating a "new" dictionary often means copying or combining existing ones.

python
1base = {"timeout": 20, "retries": 2}
2override = {"timeout": 30}
3
4merged = {**base, **override}
5print(merged)

In modern Python, the merge operator is also available:

python
merged2 = base | override
print(merged2)

This creates a new dictionary rather than mutating the original base, which is often the safer behavior in larger codebases.

Common Pitfalls

One common mistake is using square-bracket access on a key that might not exist. If missing keys are expected, get or setdefault can be safer than catching KeyError repeatedly.

Another is overusing clever comprehensions where a normal loop would be easier to maintain. Brevity is not always clarity.

The biggest practical trap is shared mutable defaults from fromkeys. That bug can hide for a long time before someone notices that multiple keys are changing together.

Finally, remember that dictionary keys should be hashable and stable. Mutable types such as lists cannot be used as keys.

Summary

  • Use literal syntax when keys and values are known directly.
  • Use dict() for keyword arguments or iterables of key-value pairs.
  • Use comprehensions for simple generated mappings.
  • Use loops when the construction logic is more complex.
  • Be careful with fromkeys() when the default value is mutable.

Course illustration
Course illustration

All Rights Reserved.