Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Python Dictionaries for Key-Value Data

Learn to create and use dictionaries for key-value data in Python. This tutorial covers dictionary creation, access, modification, and deletion, with practical exercises and troubleshooting tips.

Focus: create and use dictionaries for key-value data

Sponsored

When you start building real programs in Python, you quickly encounter a universal problem: how do you store and retrieve data that isn't just a simple list of items? Maybe you need to look up a user by their email address, or count how many times each word appears in a sentence. Using separate lists for keys and values is fragile, slow, and error-prone. Python's dictionary type (dict) solves this exact pain point — it gives you a blazing-fast, readable way to associate one piece of data (the key) with another (the value).

The problem this lesson solves

Imagine you're building a contact list. You could store names in one list and phone numbers in another, and rely on matching indices:

names = ["Alice", "Bob", "Charlie"]
numbers = ["555-1234", "555-5678", "555-9999"]

# To find Bob's number:
bob_index = names.index("Bob")
print(numbers[bob_index])  # "555-5678"

This works, but it's brittle. What if you delete a contact from names but forget to delete from numbers? What if you need to search by phone number instead of name? Every operation becomes a manual synchronization nightmare. This is the problem: when you need to map one value to another (a key to a value), sequential lists are the wrong tool. You need a data structure that stores key-value pairs directly, guarantees fast lookups by key, and keeps your code clean.

Core concept / mental model

Think of a Python dictionary as a real-world dictionary (like a book of word definitions). You look up a word (the key) and instantly find its definition (the value). The key must be unique — you can't have two identical words with different definitions. But unlike a printed dictionary, Python's dictionary is mutable and dynamic: you can add new entries, change definitions, and delete words at any time.

Pro Tip: The best mental model for a dictionary is a labeled drawer system. Each drawer has a unique label (key), and inside is the item you care about (value). To find something, you just pull the right drawer by its label — you never search through all drawers.

Key properties of Python dictionaries:

  • Unordered (Python 3.6 and earlier) — In Python 3.7+, dictionaries maintain insertion order, but you should not rely on sorting.
  • Mutable — You can add, change, or remove key-value pairs after creation.
  • Key uniqueness — Each key can appear only once. If you assign a value to an existing key, the old value is overwritten.
  • Keys must be hashable — Most immutable types (str, int, tuple, float) work as keys. Lists or other dictionaries cannot be keys.
  • Values can be any type — strings, numbers, lists, other dictionaries, functions, etc.

How it works step by step

1. Creating a dictionary

You create a dictionary using curly braces {} with colon-separated key-value pairs:

# Empty dictionary
empty_dict = {}

# Dictionary with initial data
student = {
    "name": "Maria",
    "age": 22,
    "courses": ["Math", "Physics"],
    "is_enrolled": True
}

You can also use the dict() constructor:

# Using keyword arguments
person = dict(name="James", age=30, city="Berlin")

# From a list of tuples
pairs = [("a", 1), ("b", 2), ("c", 3)]
my_dict = dict(pairs)
print(my_dict)  # {"a": 1, "b": 2, "c": 3}

2. Accessing values

Use square brackets with the key:

student = {"name": "Maria", "age": 22}
print(student["name"])  # "Maria"

Warning: If the key doesn't exist, dict[key] raises a KeyError.

To safely access a key that might be missing, use .get():

print(student.get("grade"))        # None (no error)
print(student.get("grade", "N/A")) # "N/A" (custom default)

3. Adding and modifying values

Assign to a new or existing key:

student["grade"] = "A"     # Adds new key
student["age"] = 23         # Updates existing key
student.update({"city": "Paris", "age": 24})  # Multiple at once

4. Removing key-value pairs

  • del dict[key] — Removes the key-value pair (raises KeyError if missing)
  • dict.pop(key) — Returns the value and removes the pair
  • dict.clear() — Empties the entire dictionary
user = {"id": 1, "name": "Alice", "active": True}

removed_name = user.pop("name")    # Returns "Alice", key removed
last_item = user.popitem()           # Removes and returns last inserted pair
print(user)  # {"id": 1}

Hands-on walkthrough

Let's build a word frequency counter — a classic use case that shows dictionaries in action.

text = "the quick brown fox jumps over the lazy dog"

# Create empty frequency dictionary
word_counts = {}

# Split text into words
words = text.split()

# Count each word
for word in words:
    if word in word_counts:
        word_counts[word] += 1
    else:
        word_counts[word] = 1

print(word_counts)

Expected output:

{'the': 2, 'quick': 1, 'brown': 1, 'fox': 1, 'jumps': 1, 'over': 1, 'lazy': 1, 'dog': 1}

A more Pythonic version uses .get():

word_counts = {}
for word in text.split():
    word_counts[word] = word_counts.get(word, 0) + 1

Iterating over a dictionary

Three common patterns:

# Keys only (default)
for key in student:
    print(key)

# Values
for value in student.values():
    print(value)

# Both (as tuples)
for key, value in student.items():
    print(f"{key}: {value}")

Nested dictionaries

Dictionaries can hold other dictionaries, creating complex structures:

company = {
    "engineering": {
        "manager": "Alice",
        "team_size": 12,
        "languages": ["Python", "Go"]
    },
    "design": {
        "manager": "Bob",
        "team_size": 5
    }
}

print(company["engineering"]["manager"])  # "Alice"

Compare options / when to choose what

When to use… Dictionary List Set
Store unique identifiers mapped to values ✅ Best
Ordered sequence of items ✅ Best
Checking membership (fast) ✅ Good for keys ❌ Slow ✅ Best
Storing duplicate items ❌ (keys unique) ✅ Yes
Numeric indexing ✅ Best

Variations to know:

  • collections.defaultdict — Automatically provides default values for missing keys, useful for counting or grouping.
  • collections.OrderedDict — Remembers insertion order explicitly (though regular dict does too in Python 3.7+).
  • Dictionary comprehension — Create dictionaries concisely: {x: x**2 for x in range(5)}.

Troubleshooting & edge cases

KeyError when accessing missing keys

d = {"a": 1}
print(d["b"])  # KeyError: 'b'

Fix: Use .get() or check with in first: if "b" in d:

Unhashable type as key

d = {[1, 2]: "value"}  # TypeError: unhashable type: 'list'

Fix: Use tuples (if the elements are immutable) or strings instead of lists as keys.

Modifying dictionary while iterating

for key in my_dict:
    if condition:
        del my_dict[key]  # RuntimeError: dictionary changed size during iteration

Fix: Iterate over a copy: for key in list(my_dict.keys()):

Mutable default values (common bug)

def add_student(student_dict, course="Math"):
    # Don't use mutable defaults in function parameters
    pass

This isn't a dict-specific issue, but be careful when dictionaries are used as default arguments — they persist across calls.

Merging dictionaries (Python 3.9+)

# Merge operator (Python 3.9+)
merged = dict1 | dict2

# Or the |= operator for in-place update
dict1 |= dict2

What you learned & what's next

You now understand how to create and use dictionaries for key-value data in Python. You learned: how to create dictionaries with curly braces and the dict() constructor, how to access and modify values safely with .get(), the difference between lists and dictionaries for mapping data, and how to iterate over keys, values, or both. You also practiced a real-world word-frequency counter and learned to avoid common pitfalls like KeyErrors and unhashable types.

Next step: In the following lesson, you'll explore dictionary methods and iteration patterns in depth, including advanced iteration with items(), sorting keys, and using dictionary comprehensions. You'll also learn how to combine dictionaries with other data structures like lists of dictionaries for tabular data.

Practice challenge: Create a dictionary that maps Roman numerals ("I", "V", "X", "L", "C", "D", "M") to their integer values. Then write a function that converts a Roman numeral string (like "XIV") to its integer equivalent using lookups from your dictionary.

Practice recap

Try this: Write a Python script that reads a sentence from the user, splits it into words, and uses a dictionary to count how many times each word appears. Then modify it to ignore punctuation (strip commas and periods) and handle case-insensitivity. This exercise reinforces all the key concepts from this lesson.

Common mistakes

  • Using lists to simulate key-value mapping (index-based lookup) instead of dictionaries — this breaks when data changes order.
  • Forgetting that keys must be immutable types — using a list as a key raises TypeError.
  • Not checking for key existence before access — causes KeyError. Always use .get() or 'in' check for optional keys.
  • Trying to use dictionary methods like .sort() — dictionaries don't have inherent order. Use sorted(dict.items()) instead.
  • Assuming dictionary order is guaranteed in older Python versions — relies on Python 3.7+ behavior.

Variations

  1. Use collections.defaultdict for automatic default values when counting or grouping data.
  2. Use dictionary comprehension ({k: v for k, v in iterable}) for concise dictionary construction.
  3. Use collections.OrderedDict if you need explicit order control and are targeting Python <3.7.

Real-world use cases

  • Storing user profiles by email or user ID for fast lookups in web applications.
  • Counting word frequencies in natural language processing or text analysis.
  • Mapping configuration settings (key-value pairs) from environment variables or config files.

Key takeaways

  • Dictionaries store key-value pairs and provide O(1) average lookup time for keys.
  • Create dictionaries with {} or dict(); access values with dict[key] or safer .get().
  • Keys must be immutable (strings, numbers, tuples) and unique; values can be any type.
  • Modify dictionaries by direct assignment, .update(), .pop(), or del.
  • Iterate with .keys(), .values(), or .items() for both key and value access.
  • Use .get(key, default) to avoid KeyError when a key may not exist.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.