Skip to content

Dictionaries

A dictionary is a collection of key-value pairs — like a real-world dictionary where you look up a word (key) to find its meaning (value).

Creating dictionaries

empty = {}
person = {"name": "Alice", "age": 25, "city": "Mumbai"}
prices = {"apple": 50, "banana": 30, "mango": 80}

print(empty, person, prices)

You can also use dict():

person = dict(name="Alice", age=25, city="Mumbai")
print(person)

Accessing values

Use [key] or .get():

person = {"name": "Alice", "age": 25, "city": "Mumbai"}

print(person["name"])               # "Alice"
print(person.get("age"))            # 25

# `[]` raises KeyError if missing
# print(person["email"])            # KeyError

# `.get()` returns None instead — safer
print(person.get("email"))                       # None
print(person.get("email", "no-email@example"))   # default if missing

Adding & updating

Dicts are mutable. Assign a key to create or update:

person = {"name": "Alice", "age": 25}

# Add new key
person["city"] = "Mumbai"

# Update existing
person["age"] = 26

print(person)

# Update many at once
person.update({"job": "Engineer", "age": 27})
print(person)

Removing keys

person = {"name": "Alice", "age": 25, "city": "Mumbai", "job": "Engineer"}

del person["city"]                # remove by key
print(person)

age = person.pop("age")           # remove + return value
print(age, person)

last = person.popitem()           # remove + return LAST inserted (key, value)
print(last, person)

person.clear()
print(person)                     # {}

Checking if a key exists

person = {"name": "Alice", "age": 25}

print("name" in person)        # True — checks KEYS by default
print("Alice" in person)        # False — that's a value

# Check values
print("Alice" in person.values())   # True

Looping over a dict

person = {"name": "Alice", "age": 25, "city": "Mumbai"}

# Default loop gives keys
for key in person:
    print(key)

print("---")

# Get keys, values, or both
for key in person.keys():
    print(key)

print("---")
for value in person.values():
    print(value)

print("---")
for key, value in person.items():
    print(f"{key}: {value}")

Dict comprehension

Same idea as list comprehension, but builds a dict:

# {key: value for ... in ...}
squares = {x: x*x for x in range(5)}
print(squares)         # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# Swap keys and values
person = {"name": "Alice", "age": 25}
swapped = {v: k for k, v in person.items()}
print(swapped)         # {'Alice': 'name', 25: 'age'}

# Filter
prices = {"apple": 50, "banana": 30, "mango": 80, "guava": 25}
cheap = {fruit: price for fruit, price in prices.items() if price < 50}
print(cheap)

Nested dicts

Common pattern for structured data:

users = {
    "alice": {"age": 25, "city": "Mumbai"},
    "bob":   {"age": 30, "city": "Delhi"},
    "carol": {"age": 22, "city": "Bangalore"},
}

# Access
print(users["alice"]["city"])      # "Mumbai"

# Add a new user
users["dave"] = {"age": 40, "city": "Chennai"}

# Loop through
for name, info in users.items():
    print(f"{name} ({info['age']}) from {info['city']}")

Common patterns

Counting things

text = "the quick brown fox jumps over the lazy dog the fox"
counts = {}

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

print(counts)

Or use collections.Counter — built for this:

from collections import Counter

text = "the quick brown fox jumps over the lazy dog the fox"
counts = Counter(text.split())

print(counts)
print(counts.most_common(3))       # top 3 most common

Grouping items

from collections import defaultdict

people = [
    ("Alice", "Mumbai"),
    ("Bob",   "Delhi"),
    ("Carol", "Mumbai"),
    ("Dave",  "Delhi"),
    ("Eve",   "Bangalore"),
]

by_city = defaultdict(list)
for name, city in people:
    by_city[city].append(name)

print(dict(by_city))

defaultdict(list) auto-creates an empty list when you access a missing key — no if key not in dict needed.

Switching on a value (dict-as-dispatch)

def add(a, b): return a + b
def sub(a, b): return a - b
def mul(a, b): return a * b

ops = {"+": add, "-": sub, "*": mul}

print(ops["+"](3, 4))    # 7
print(ops["*"](3, 4))    # 12

Dictionary vs other types

When to use Pick
Look up a value by a key (name, ID, etc.) dict
Just a sequence of items list
Just need uniqueness set
Fixed-size grouping that won't change tuple

Mini-project — word frequency

text = """
Python is great. Python is easy to learn.
Python has clear syntax. Python is popular.
"""

# Clean and split
words = text.lower().replace(".", "").split()

# Count
freq = {}
for w in words:
    freq[w] = freq.get(w, 0) + 1

# Sort by frequency, descending
for word, count in sorted(freq.items(), key=lambda x: -x[1]):
    print(f"{word:10} {count}")

Practice

What does this print?

Expected: unknown

person = {"name": "Alice", "age": 25}
print(person.get("city", "unknown"))

Print 'Bob' without crashing if the key is missing

Expected: Bob

users = {"alice": "Alice", "bob": "Bob"}
print(users["BOB"])     # bug: KeyError — keys are case-sensitive and missing

Quiz — Quick check

What you remember

Q1. What does person.get("missing") return if "missing" isn't a key?

  • Raises KeyError
  • Returns None
  • Returns 0
  • Returns False

Why: .get() returns None for missing keys, unlike person["missing"] which raises KeyError. You can supply a fallback: person.get("key", "default").

Q2. Which loop pattern gives you both keys AND values?

  • for x in d:
  • for x in d.keys():
  • for x in d.values():
  • for k, v in d.items():

Why: .items() yields (key, value) pairs. The default for x in d: iterates over keys only.

Q3. What type can be used as a dict key?

  • Only strings
  • Anything immutable (str, int, float, tuple, frozenset)
  • Anything
  • Only strings and ints

Why: Dict keys must be hashable, which essentially means immutable. Lists and dicts can't be keys; tuples can.

Common doubts

Are dicts ordered in Python?

Yes, since Python 3.7 — dicts preserve insertion order as part of the language spec. Before 3.7 (and CPython 3.6 as an implementation detail), they were unordered. Today, for k in d: reliably iterates in insertion order.

When should I use defaultdict vs a regular dict?

Use defaultdict(list) (or defaultdict(int), etc.) when you're building up grouped data and want to skip the if key not in d: boilerplate. Use a regular dict when keys are known up front or when missing keys should raise.

Why does d.keys() not return a list?

It returns a view object that's tied to the dict — it updates if the dict changes, and avoids the cost of copying every key into a list. If you really need a list, do list(d.keys()). Same for .values() and .items().

What's next

Modules & Built-in Functions