🗂️ Python Dictionaries

What is a Dictionary in Python?

A complete beginner-friendly guide to Python Dictionaries — covering creation, key-value pairs, methods, nested dictionaries, dictionary comprehension, hashing internals, merging, common errors, and why dictionaries are Python's most-used data structure.

📅

Last Updated

March 2026

⏱️

Read Time

28 min

🎯

Level

Beginner

What is a Dictionary in Python?

A dictionary in Python is a built-in data structure that stores data as key-value pairs. Instead of accessing items by numeric position like a list, you access items in a dictionary using a unique, descriptive key. Every key maps to exactly one value, and that value can be anything — a number, string, list, another dictionary, or even a function.

Dictionaries are written using curly braces {} with each entry separated by a colon: {"name": "Aman", "age": 25}. Here, "name" and "age" are keys, while "Aman" and 25 are their corresponding values. This structure mirrors real-world lookups — a phone book, an English dictionary, or a database record — where you look something up by a name, not by its position in a list.

Like sets, dictionaries are built on a hash table internally. When you write my_dict["name"], Python hashes the key "name" and jumps directly to the memory slot storing its value — giving O(1) average time complexity for lookups, insertions, and deletions, regardless of how large the dictionary grows. This is the single biggest reason dictionaries are used so heavily throughout the Python language and standard library.

A crucial detail that changed the language: starting with Python 3.7, dictionaries officially preserve insertion order as a guaranteed language feature (it was an implementation detail in 3.6). This means iterating over a dictionary today returns keys in the exact order they were added — a behaviour many other languages' hash maps do not offer.

In short: a dictionary is Python's tool for storing labelled, fast-lookup data — anywhere you would naturally say "give me the value for this name" rather than "give me the third item", a dictionary is the right structure. It is arguably the single most important and most-used data structure in the entire Python language — even Python's own internals, like object attributes and namespaces, are implemented using dictionaries.

How to Create a Dictionary in Python

Python offers several ways to build a dictionary, each suited to different situations. Here are the five you'll use most often.

1. Using Curly Braces {}

🐍 Pythoncreate_dict_literal.py
student = {"name": "Riya", "age": 21, "course": "B.Tech"}
print(student)
print(type(student))

Output

{'name': 'Riya', 'age': 21, 'course': 'B.Tech'} <class 'dict'>

2. Using the dict() Constructor

The dict() constructor is useful when your keys are valid variable names — you can pass them directly as keyword arguments, without quotes.

🐍 Pythondict_constructor.py
student = dict(name="Riya", age=21, course="B.Tech")
print(student)   # {'name': 'Riya', 'age': 21, 'course': 'B.Tech'}

3. Creating an Empty Dictionary

Unlike sets, dictionaries do not have a naming trap here — {} genuinely creates an empty dictionary. This is actually the reverse situation of Python sets, where {} defaults to dict precisely because dict is the more common, default use of curly braces.

🐍 Pythonempty_dict.py
empty = {}
print(type(empty))   # <class 'dict'> — this really is a dict

4. From a List of Tuples — dict()

🐍 Pythondict_from_pairs.py
pairs = [("a", 1), ("b", 2), ("c", 3)]
d = dict(pairs)
print(d)   # {'a': 1, 'b': 2, 'c': 3}

5. Dictionary Comprehension

Just like list and set comprehension, Python supports building a dictionary in a single expressive line.

🐍 Pythondict_comprehension.py
squares = {x: x**2 for x in range(6)}
print(squares)   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Important rule: dictionary keys must be unique and hashable (immutable) — strings, numbers, and tuples all qualify. Values, on the other hand, can be absolutely anything, including lists, other dictionaries, or duplicates of each other.

Key Characteristics of Python Dictionaries

Dictionaries have their own distinct rules that separate them from lists, tuples, and sets. Here are the ten most important ones to internalise.

🔑
Key-Value Pairs

Every item is stored as a key mapped to a value — you retrieve data by key, not by numeric position.

📌
Insertion Order Preserved

Since Python 3.7, dictionaries officially guarantee that keys keep the order in which they were inserted when you iterate over them.

🚫
Keys Must Be Unique

If you assign a value to a key that already exists, the old value is simply overwritten — a dictionary can never have two identical keys.

🔒
Keys Must Be Hashable

Only immutable types — strings, numbers, and tuples — are valid keys. Lists and other dictionaries cannot be used as keys.

🎨
Values Can Be Anything

Unlike keys, values have no restrictions — they can be strings, numbers, lists, other dictionaries, functions, or even objects.

✏️
Mutable

You can add, update, or delete key-value pairs after the dictionary is created — the dictionary itself can grow, shrink, and change.

⚡
Fast Lookups

Retrieving a value by key runs in O(1) average time thanks to hashing — regardless of how many items the dictionary holds.

🚷
No Positional Indexing

You cannot access my_dict[0] expecting 'the first item' — indexing a dict always means looking up a key, not a position.

🪆
Supports Nesting

A dictionary value can itself be another dictionary, letting you model deeply structured, tree-like data such as JSON.

🧮
Built on Hash Tables

CPython implements dictionaries using an open-addressing hash table combined with a separate insertion-order array — the technology that also powers Python sets.

How Python Looks Up a Dictionary Value — Flowchart

Every time you write my_dict[key], Python runs the key through a precise internal lookup pipeline before returning a value. The flowchart below traces that exact process, and also shows what happens when the key doesn't exist.

📝 my_dict[key]Lookup requested
hashing
🔑 Compute hash(key)Python calls the key's __hash__()
modulo table size
📍 Locate Hash BucketHash value maps to a table slot
check slot
❓ Key Found in Bucket?Compare stored key with ==
match — same key
🔍 Resolve CollisionProbe next slot if hashes clashed
match found after probing
🚫 Raise KeyErrorKey not present anywhere
✅ Return ValueMatching key's value retrieved

Code Execution Flow — from source to output

Key insight: this is exactly why dictionary keys must be hashable and immutable — if a key's hash could change after insertion, Python would look in the wrong bucket entirely and silently fail to find data that is actually there.

Accessing and Modifying Dictionary Values

📖 Reading Values

  • ▶

    my_dict[key] — returns the value for key, raises KeyError if the key doesn't exist.

  • ▶

    my_dict.get(key) — returns the value for key, or None (no error) if the key doesn't exist.

  • ▶

    my_dict.get(key, default) — returns a custom fallback value instead of None when the key is missing.

🐍 Pythonreading_values.py
student = {"name": "Riya", "age": 21}

print(student["name"])            # Riya
print(student.get("grade"))        # None — no error
print(student.get("grade", "N/A")) # N/A — custom default

✏️ Adding and Updating Values

🐍 Pythonadding_updating.py
student["grade"] = "A"        # adds a new key
student["age"] = 22           # overwrites existing key's value
student.update({"city": "Patna", "age": 23})  # updates multiple keys at once
print(student)

🗑️ Removing Values

  • ▶

    del my_dict[key] — deletes the key-value pair, raises KeyError if key doesn't exist.

  • ▶

    my_dict.pop(key) — removes key and returns its value, raises KeyError if missing (unless a default is given).

  • ▶

    my_dict.popitem() — removes and returns the last inserted key-value pair as a tuple (LIFO order).

  • ▶

    my_dict.clear() — removes every key-value pair, leaving an empty dictionary.

🐍 Pythonremoving_values.py
del student["city"]
grade = student.pop("grade", "N/A")   # safe removal with default
last_item = student.popitem()          # removes most recently added pair
student.clear()
print(student)   # {}

Complete Python Dictionary Methods — Cheat Sheet

Here is every commonly used dictionary method in one reference table, organised by what it does.

MethodCategoryDescriptionReturns
get(key, default)ReadSafely retrieves a value without raising KeyErrorValue or default
keys()ReadReturns a view of all keysdict_keys
values()ReadReturns a view of all valuesdict_values
items()ReadReturns a view of all (key, value) pairsdict_items
setdefault(key, default)WriteReturns value if key exists, else inserts defaultValue
update(other)WriteMerges another dict or key-value pairs inNone
pop(key, default)WriteRemoves key and returns its valueValue
popitem()WriteRemoves and returns the last-inserted pair(key, value) tuple
clear()WriteRemoves every key-value pairNone
copy()UtilityReturns a shallow copy of the dictionarydict
len(my_dict)UtilityReturns the number of key-value pairs (built-in)int
key in my_dictUtilityChecks whether a key exists (built-in operator)bool

Iterating Over a Dictionary

Dictionaries offer three distinct "views" for iteration — over keys, over values, or over both together. Since Python 3.7, all three respect the guaranteed insertion order.

🐍 Pythoniterating_dict.py
scores = {"Aman": 88, "Zara": 95, "Kabir": 74}

for key in scores:                 # iterates over keys by default
    print(key)

for value in scores.values():      # iterates over values only
    print(value)

for key, value in scores.items():  # iterates over both together
    print(f"{key} scored {value}")

.items() is by far the most commonly used pattern in real code — it lets you unpack the key and value directly in the loop header, avoiding a separate lookup like scores[key] inside the loop body.

Nested Dictionaries

A dictionary value can itself be another dictionary — this is called nesting, and it's the foundation of how Python represents structured data such as JSON API responses, configuration files, and database records.

🐍 Pythonnested_dict.py
company = {
    "name": "Tech Sustainify",
    "founder": {
        "name": "Ashish",
        "location": "India"
    },
    "employees": [
        {"name": "Riya", "role": "Developer"},
        {"name": "Zara", "role": "Designer"}
    ]
}

print(company["founder"]["name"])          # Ashish
print(company["employees"][0]["role"])     # Developer

When accessing deeply nested keys that might not exist, chaining .get() calls avoids crashing your program: company.get("founder", {}).get("email", "N/A") safely returns "N/A" instead of raising a KeyError if "email" is missing.

Dictionary Comprehension — A Deeper Look

Dictionary comprehension follows the pattern {key_expr: value_expr for item in iterable if condition}, letting you build a dictionary from any iterable in a single readable line.

  • ▶

    Inverting a dictionary — {v: k for k, v in original.items()} swaps every key with its value, useful for reverse lookups.

  • ▶

    Filtering entries — {k: v for k, v in scores.items() if v >= 90} keeps only key-value pairs that meet a condition.

  • ▶

    Building from two lists — {k: v for k, v in zip(names, ages)} pairs up two parallel lists into a dictionary.

  • ▶

    Transforming values — {k: v.upper() for k, v in data.items()} applies a transformation to every value while keeping the keys unchanged.

🐍 Pythondict_comprehension_examples.py
scores = {"Aman": 88, "Zara": 95, "Kabir": 74}

toppers = {k: v for k, v in scores.items() if v >= 85}
print(toppers)   # {'Aman': 88, 'Zara': 95}

reversed_lookup = {v: k for k, v in scores.items()}
print(reversed_lookup)   # {88: 'Aman', 95: 'Zara', 74: 'Kabir'}

Merging Dictionaries in Python

Python has evolved several ways to merge two dictionaries. Knowing all of them helps you read code written across different Python versions.

MethodPython VersionModifies Original?Example
update()All versions✅ Yes — modifies in placea.update(b)
{**a, **b}3.5+❌ No — creates a new dictmerged = {**a, **b}
a | b (merge operator)3.9+❌ No — creates a new dictmerged = a | b
a |= b (in-place merge)3.9+✅ Yes — modifies in placea |= b
🐍 Pythonmerging_dicts.py
defaults = {"theme": "light", "font_size": 12}
user_prefs = {"font_size": 16}

# Python 3.9+ merge operator
final_settings = defaults | user_prefs
print(final_settings)   # {'theme': 'light', 'font_size': 16}

In every merge method above, when the same key appears in both dictionaries, the value from the right-hand (or later) dictionary wins. This is why user_prefs overrides defaults for font_size in the example above.

Dictionary vs List vs Tuple vs Set — Comparison

Choosing the right built-in collection depends on whether you need order, uniqueness, mutability, or key-based lookup.

FeatureDictionaryListTupleSet
StoresKey-value pairsOrdered itemsOrdered itemsUnique items
Ordered?✅ Yes (3.7+)✅ Yes✅ Yes❌ No
Allows Duplicates?❌ No (keys)✅ Yes✅ Yes❌ No
Mutable?✅ Yes✅ Yes❌ No✅ Yes
Access ByKeyIndexIndexValue (membership only)
Syntax{'a': 1}[1, 2, 3](1, 2, 3){1, 2, 3}
Lookup Speed⚡ O(1) average🐢 O(n)🐢 O(n)⚡ O(1) average
Best ForLabelled/structured data, fast key lookupOrdered sequencesFixed, unchanging recordsUniqueness, set math

Advantages and Disadvantages of Python Dictionaries

Dictionaries are extraordinarily useful, but understanding their trade-offs helps you choose the right structure every time.

✅ Advantages
Extremely Fast LookupsRetrieving a value by key runs in O(1) average time, regardless of dictionary size — ideal for large datasets that need frequent lookups by name or ID.
Self-Documenting DataNamed keys like 'name' or 'price' make code far more readable than positional access like my_list[3], where the meaning of index 3 isn't obvious.
Flexible Value TypesValues can be numbers, strings, lists, functions, or even other dictionaries, making dicts perfect for representing complex, real-world structured data.
Guaranteed Insertion OrderSince Python 3.7, iteration order matches insertion order, which is a language guarantee you can safely rely on.
Native JSON CompatibilityPython dictionaries map directly onto JSON objects, making dicts the natural structure for working with APIs, config files, and web data.
❌ Disadvantages
No Positional IndexingYou cannot access 'the third entry' the way you can with a list — dictionaries are accessed purely by key.
Keys Must Be HashableLists and other dictionaries cannot be used as keys, which occasionally requires restructuring your data (e.g. converting a list key into a tuple).
Higher Memory OverheadThe underlying hash table and separate order-tracking array mean dictionaries typically use more memory per item than an equivalent list.
KeyError RiskDirect key access (my_dict[key]) raises a KeyError if the key is missing, requiring careful use of .get() or membership checks in uncertain cases.
Not Suitable for Purely Sequential DataIf your data doesn't naturally have labels — just an ordered sequence of values — a list is simpler and more appropriate than a dictionary.

How Python Dictionaries Work Internally — Architecture

The diagram below shows the internal layers behind every dictionary operation — from the Python code you write, down to the compact hash table CPython maintains in memory since the 3.6 redesign.

Your Python Code
my_dict = {'a': 1}my_dict['b'] = 2for k, v in my_dict.items():
CPython dict Object API
dict_setitem()dict_getitem()dict_delitem()
Hashing Layer
__hash__() called on each keyHash value computed (SipHash for strings)
Compact Hash Table (3.6+)
Sparse index array (hash → slot)Dense array preserving insertion orderAutomatic resizing as items are added
Memory Management
Reference countingGarbage collector for cyclic references
Hardware
CPURAM

Architecture Diagram

Since Python 3.6, CPython uses a clever "compact dict" design — a sparse index array that maps hashes to positions, alongside a separate dense array that stores the actual key-value pairs in insertion order. This redesign is what made guaranteed ordering possible and reduced memory usage compared to the older implementation, a rare case of getting both benefits at once.

Dictionary Performance — Big-O Complexity Table

Understanding the time complexity of common operations helps you judge when a dictionary is the right performance choice.

OperationDict (Average)Dict (Worst Case)List (Average, by value)
Lookup by key (my_dict[k])O(1)O(n)O(n)
Insert / update a keyO(1)O(n)O(1) (append only)
Delete a keyO(1)O(n)O(n)
Membership test (k in dict)O(1)O(n)O(n)
Iteration over all itemsO(n)O(n)O(n)

The "worst case" column applies only under heavy hash collisions, which are extremely rare with Python's well-distributed hash function — this is why dictionaries are described as O(1) "on average" in virtually all practical scenarios.

Your First Python Dictionary Program

Let's combine everything into one small program — building a dictionary, reading from it safely, updating it, and looping over it, exactly the pattern you'll reuse constantly in real projects.

🐍 Pythonfirst_dict_program.py
# A simple inventory system
inventory = {"apples": 50, "bananas": 30, "oranges": 20}

inventory["grapes"] = 15                 # add a new item
inventory["bananas"] -= 10                # update existing quantity

for item, quantity in inventory.items():
    print(f"{item}: {quantity} units")

print("Total items:", sum(inventory.values()))

Output

apples: 50 units bananas: 20 units oranges: 20 units grapes: 15 units Total items: 105

Practice This Code — Live Editor

Line-by-Line Explanation

  • ▶

    inventory = {...} — creates a dictionary literal mapping each fruit name (key) to its stock count (value).

  • ▶

    inventory["grapes"] = 15 — since 'grapes' doesn't exist yet, this adds a brand-new key-value pair.

  • ▶

    inventory["bananas"] -= 10 — since 'bananas' already exists, this updates its existing value instead of adding a duplicate key.

  • ▶

    inventory.items() — returns every key-value pair, letting the loop unpack both item and quantity directly.

  • ▶

    sum(inventory.values()) — .values() extracts just the numbers, which sum() then adds together.

Common Errors and Gotchas When Using Dictionaries

These are the mistakes that trip up nearly every Python learner the first time they work with dictionaries in depth.

  • ▶

    KeyError on Missing Keys — my_dict["missing_key"] crashes the program if the key isn't present. Use .get() or check 'key in my_dict' first when you're unsure.

  • ▶

    TypeError: unhashable type: 'list' — you cannot use a list or another dictionary as a key, since both are mutable and unhashable. Use a tuple instead if you need a compound key.

  • ▶

    Assuming .keys() Returns a List — .keys(), .values(), and .items() return special 'view' objects, not lists. They update automatically if the dictionary changes, and support 'in' checks efficiently, but need list(...) wrapped around them if you need actual list operations like indexing.

  • ▶

    Mutable Default Values Shared Across Keys — using {}.fromkeys(keys, []) makes every key point to the exact same list object, so modifying one key's list unexpectedly changes them all. Use a dict comprehension instead: {k: [] for k in keys}.

  • ▶

    Modifying a Dictionary While Iterating — adding or removing keys inside a for loop over the same dictionary raises RuntimeError: dictionary changed size during iteration. Iterate over list(my_dict.items()) instead if you need to modify it during the loop.

  • ▶

    Confusing == with is for Dictionary Comparison — two separate dictionaries with identical content compare equal with ==, but are not the same object in memory, so 'is' returns False even though the data matches.

Where Are Python Dictionaries Used? — Real-World Applications

Dictionaries are arguably Python's single most-used data structure. Here is where you will actually reach for a dict in real, professional code:

  • ▶

    🌐 Working with JSON & APIs — every JSON object returned by a web API is automatically parsed into a Python dictionary, making dicts essential for virtually all web and API development.

  • ▶

    ⚙️ Configuration & Settings — application settings, environment variables, and feature flags are almost always modelled as dictionaries mapping setting names to their values.

  • ▶

    🧮 Counting & Frequency Analysis — counting word frequency in text, votes in a poll, or occurrences of any item is a natural dictionary pattern: word_counts[word] = word_counts.get(word, 0) + 1.

  • ▶

    🗄️ Caching & Memoization — storing previously computed results keyed by their input arguments (a cache) avoids redoing expensive calculations, and is implemented almost universally with a dict.

  • ▶

    📇 Representing Records — a single student, product, or user is naturally modelled as one dictionary, with keys like 'name', 'id', and 'email' — mirroring a row in a database.

  • ▶

    🕸️ Graph Representation — graphs are commonly represented as a dictionary mapping each node to a list of its neighbours, powering algorithms like BFS, DFS, and shortest-path search.

  • ▶

    🏷️ Grouping Data — grouping a list of items by a shared attribute (e.g. grouping employees by department) is typically done by building a dictionary of lists, keyed by that attribute.

  • ▶

    🐍 Python's Own Internals — every object's attributes, every module's namespace, and every function's local variables in CPython are themselves implemented internally using dictionaries.

Why Should You Learn Python Dictionaries in 2026?

If you only deeply master one Python data structure, it should be the dictionary. Here's why it consistently pays off across every area of Python development:

  • ▶

    🌍 The Language of APIs & JSON — nearly every external data source you'll work with — REST APIs, config files, NoSQL databases — arrives as JSON, which maps directly onto Python dictionaries.

  • ▶

    🎯 Extremely Common in Interviews — 'count word frequency', 'group by category', and 'build a cache' are classic interview problems, and all three are solved cleanly with a dictionary.

  • ▶

    ⚡ Massive Performance Advantage — replacing a linear search through a list with a dictionary lookup is one of the highest-impact, easiest optimisations you can make in everyday code.

  • ▶

    🧠 Enables Readable, Self-Documenting Code — named keys like order['total_price'] communicate intent far better than an unlabeled positional value like order[4].

  • ▶

    🔗 Foundation for Advanced Python — kwargs, class __dict__ attributes, namespaces, and even Python's own object model are all built on the same dictionary concept you learn here.

Python Dictionary Interview Questions — Beginner Level

These are the most frequently asked interview questions specifically about Python dictionaries. Practice explaining each answer in your own words.

Practice Questions — Test Your Knowledge of Dictionaries

Try to work out each answer yourself before revealing it — active recall is one of the fastest ways to lock in a new concept.

1. What does {"a": 1, "a": 2} evaluate to, and why?

Easy

2. What is the output of len({"x": 1, "y": 2, "z": 3})?

Easy

3. What error does {[1, 2]: "value"} raise, and why?

Easy

4. Given d = {"a": 1, "b": 2}, what does d.setdefault("c", 3) do, and what does d look like afterward?

Medium

5. Why does {}.fromkeys(["a", "b"], []) create a subtle bug if you later modify one key's list?

Medium

6. How would you count how many times each word appears in a list of words, in three lines or fewer?

Medium

7. What is the difference between dict1.update(dict2) and dict1 | dict2?

Hard

8. Write a one-line dictionary comprehension that inverts a dictionary (swaps its keys and values), assuming all original values are unique and hashable.

Hard

Conclusion — Why the Dictionary is Python's MVP Data Structure

The Python dictionary is, without exaggeration, the most important data structure in the entire language. It is the natural home for anything with a name or a label — a user profile, an API response, a configuration file, a word count, a cache — and its O(1) average lookup speed means it stays fast even as your data grows into the millions of entries.

At the same time, dictionaries are not a universal replacement for lists, tuples, or sets. If your data is a plain, unlabeled sequence, or you need strict positional access, a list is simpler and clearer. If you only care about uniqueness and set-theory comparisons, a set is the leaner choice. Knowing when a dictionary is genuinely the right fit — versus reaching for it out of habit — is what separates a beginner from a confident Python developer.

Your SituationShould You Use a Dictionary?
Data has a clear label or name for each value✅ Yes — keys make your code self-documenting
You need fast lookups by name/ID on large data✅ Yes — O(1) average beats scanning a list
Working with JSON, APIs, or config files✅ Yes — dicts map directly onto JSON objects
Counting or grouping items by a category✅ Yes — the classic dict-of-counts / dict-of-lists pattern
Data is a plain, unlabeled ordered sequence❌ No — use a list instead
You only need uniqueness, not key-value pairing❌ No — use a set instead
Data must never change after creation⚠️ Consider a tuple, or types.MappingProxyType for a read-only dict view

The next step in your Python journey is to practise converting a few of your existing list-of-tuples or parallel-list patterns into dictionaries — you'll notice your code becomes both more readable and measurably faster whenever lookups by name are involved. Continue on to Python Functions next, since dictionaries are heavily used for keyword arguments (**kwargs) and default parameter patterns. 🗂️

Frequently Asked Questions (FAQ)