Python · Syntax · Beginner

Dictionary Methods

10 tasks

Learn all essential dictionary methods and dict comprehensions for clean and efficient data manipulation.

Dictionary Methods

#
A dictionary is an unordered collection of key-value pairs. Keys must be immutable (strings, numbers, tuples); values can be anything. Dictionaries are **mutable** — you can add, update, and delete entries. ## Reading safely with get() ```python user = {"name": "Alice", "age": 30} print(user["name"]) # "Alice" print(user.get("email")) # None — no KeyError! print(user.get("email", "not set")) # "not set" ``` Always prefer `get()` over `[]` when a key might be absent. Direct `[]` access raises `KeyError` if the key does not exist. ## setdefault() ```python d = {} d.setdefault("count", 0) # sets "count" = 0 only if it doesn't exist d["count"] += 1 print(d) # {"count": 1} # Classic word-counting pattern: text = "apple banana apple cherry apple" freq = {} for word in text.split(): freq.setdefault(word, 0) freq[word] += 1 print(freq) # {"apple": 3, "banana": 1, "cherry": 1} ``` ## update() ```python defaults = {"color": "blue", "size": 10, "shape": "circle"} overrides = {"color": "red", "weight": 5} defaults.update(overrides) print(defaults) # {"color": "red", "size": 10, "shape": "circle", "weight": 5} ``` `update()` modifies in place. For a non-mutating merge use `{**d1, **d2}` (Python 3.5+) or `d1 | d2` (Python 3.9+). ## pop() and popitem() ```python d = {"a": 1, "b": 2, "c": 3} val = d.pop("b") # removes key "b", returns 2 print(val, d) # 2 {"a": 1, "c": 3} val = d.pop("x", "default") # returns "default" — no KeyError print(val) # "default" key, val = d.popitem() # removes and returns last inserted (k, v) print(key, val) # "c" 3 ``` ## keys(), values(), items() ```python person = {"name": "Bob", "age": 25, "city": "Kyiv"} print(list(person.keys())) # ["name", "age", "city"] print(list(person.values())) # ["Bob", 25, "Kyiv"] print(list(person.items())) # [("name", "Bob"), ("age", 25), ("city", "Kyiv")] # Iterate over key-value pairs for key, value in person.items(): print(f"{key}: {value}") ``` ## copy() and clear() ```python original = {"a": 1, "b": 2} copy = original.copy() # shallow copy copy["c"] = 3 print(original) # {"a": 1, "b": 2} — unchanged original.clear() print(original) # {} ```

Dict Comprehension & Nested Dicts

#
## Dict comprehension Dict comprehension creates a new dictionary from any iterable in a single, readable expression. ```python # Basic: {key: value for item in iterable} squares = {x: x**2 for x in range(1, 6)} print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25} # From two lists using zip keys = ["a", "b", "c"] values = [1, 2, 3] d = {k: v for k, v in zip(keys, values)} print(d) # {"a": 1, "b": 2, "c": 3} # With condition (filter) even_squares = {x: x**2 for x in range(10) if x % 2 == 0} print(even_squares) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64} # Transform existing dict prices = {"apple": 1.2, "banana": 0.5, "cherry": 3.0} discounted = {item: round(price * 0.9, 2) for item, price in prices.items()} print(discounted) # {"apple": 1.08, "banana": 0.45, "cherry": 2.7} ``` ## Inverting a dictionary ```python original = {"a": 1, "b": 2, "c": 3} inverted = {v: k for k, v in original.items()} print(inverted) # {1: "a", 2: "b", 3: "c"} ``` Works only when all values are unique and hashable. ## Nested dictionaries ```python users = { "alice": {"age": 30, "role": "admin"}, "bob": {"age": 25, "role": "user"}, } # Access nested value print(users["alice"]["role"]) # "admin" # Safe access — chain get() role = users.get("charlie", {}).get("role", "guest") print(role) # "guest" — no KeyError even if "charlie" doesn't exist # Update nested value users["alice"]["age"] = 31 ``` ## Grouping with dicts ```python words = ["apple", "ant", "banana", "bear", "cherry"] by_letter = {} for word in words: letter = word[0] by_letter.setdefault(letter, []) by_letter[letter].append(word) print(by_letter) # {"a": ["apple", "ant"], "b": ["banana", "bear"], "c": ["cherry"]} ``` ## Merging dicts (Python 3.9+) ```python d1 = {"a": 1, "b": 2} d2 = {"b": 3, "c": 4} merged = d1 | d2 # new dict, d2 wins on conflicts print(merged) # {"a": 1, "b": 3, "c": 4} d1 |= d2 # update d1 in place print(d1) # {"a": 1, "b": 3, "c": 4} ```

Dictionary Methods Reference

#
## Core methods | Method | What it does | Returns | |---|---|---| | `d[key]` | Get value (KeyError if missing) | value | | `d.get(key)` | Get value or `None` | value or None | | `d.get(key, default)` | Get value or default | value or default | | `d[key] = val` | Set / update key | — | | `d.setdefault(key, default)` | Set key to default only if absent, return value | value | | `d.update(other)` | Merge `other` into `d` (in place) | `None` | | `d.pop(key)` | Remove and return value (KeyError if missing) | value | | `d.pop(key, default)` | Remove and return value or default | value or default | | `d.popitem()` | Remove and return last (key, value) pair | (key, value) | | `d.keys()` | View of all keys | dict_keys | | `d.values()` | View of all values | dict_values | | `d.items()` | View of all (key, value) pairs | dict_items | | `d.copy()` | Shallow copy | new dict | | `d.clear()` | Remove all entries | `None` | | `key in d` | Check if key exists | bool | | `len(d)` | Number of key-value pairs | int | ## Dict comprehension syntax ```python {key_expr: val_expr for var in iterable} {key_expr: val_expr for var in iterable if condition} {key_expr: val_expr for k, v in d.items()} ``` ## Merging dicts ```python # Python 3.5+: unpacking merged = {**d1, **d2} # Python 3.9+: | operator merged = d1 | d2 d1 |= d2 # in-place # All versions: update d1.update(d2) ``` ## Safe nested access pattern ```python # Chain .get() to avoid KeyError at any level value = data.get("user", {}).get("address", {}).get("city", "unknown") ``` ## Common patterns ```python # Word frequency freq = {} for word in text.split(): freq[word] = freq.get(word, 0) + 1 # Group items by category groups = {} for item in items: groups.setdefault(item.category, []).append(item) # Invert mapping inv = {v: k for k, v in d.items()} # Filter dict by value filtered = {k: v for k, v in d.items() if v > 0} ```
01

Safe Config Read

#

Write a function `get_setting(config, key, default=None)` that safely reads a value from a config dictionary. If the key exists, return its value; otherwise return `default`. Example: `get_setting({"debug": True}, "debug")` → `True`, `get_setting({"debug": True}, "port", 8080)` → `8080`.

def get_setting(config, key, default=None):
    pass


print(get_setting({"debug": True}, "debug"))          # True
print(get_setting({"debug": True}, "port", 8080))     # 8080
print(get_setting({"debug": True}, "host"))           # None
Solution
def get_setting(config, key, default=None):
    return config.get(key, default)


print(get_setting({"debug": True}, "debug"))          # True
print(get_setting({"debug": True}, "port", 8080))     # 8080
print(get_setting({"debug": True}, "host"))           # None
02

Word Frequency

#

Write a function `word_freq(text)` that returns a dictionary mapping each word to how many times it appears. Words should be lowercased and stripped of punctuation (you can assume only spaces separate words for simplicity). Example: `word_freq("the cat sat the cat")` → `{"the": 2, "cat": 2, "sat": 1}`.

def word_freq(text):
    pass


print(word_freq("the cat sat the cat"))
# {"the": 2, "cat": 2, "sat": 1}
Solution
def word_freq(text):
    counts = {}
    for word in text.lower().split():
        counts[word] = counts.get(word, 0) + 1
    return counts


print(word_freq("the cat sat the cat"))
# {"the": 2, "cat": 2, "sat": 1}
03

Merge with Override

#

Write a function `merge(base, overrides)` that returns a new dictionary with all keys from `base`, but any key present in `overrides` takes the value from `overrides`. The original dicts must not be modified. Example: `merge({"a": 1, "b": 2}, {"b": 99, "c": 3})` → `{"a": 1, "b": 99, "c": 3}`.

def merge(base, overrides):
    pass


print(merge({"a": 1, "b": 2}, {"b": 99, "c": 3}))
# {"a": 1, "b": 99, "c": 3}
Solution
def merge(base, overrides):
    return {**base, **overrides}


print(merge({"a": 1, "b": 2}, {"b": 99, "c": 3}))
# {"a": 1, "b": 99, "c": 3}
04

Remove Key Safely

#

Write a function `remove_key(d, key)` that removes `key` from dictionary `d` if it exists, and returns the removed value. If the key does not exist, return `None` without raising an error. The function should modify `d` in place. Example: `d = {"a": 1, "b": 2}; remove_key(d, "a")` → returns `1`, `d` becomes `{"b": 2}`.

def remove_key(d, key):
    pass


d = {"a": 1, "b": 2}
print(remove_key(d, "a"))   # 1
print(d)                    # {"b": 2}
print(remove_key(d, "x"))   # None
Solution
def remove_key(d, key):
    return d.pop(key, None)


d = {"a": 1, "b": 2}
print(remove_key(d, "a"))   # 1
print(d)                    # {"b": 2}
print(remove_key(d, "x"))   # None
05

Squares Dict

#

Write a function `squares_dict(n)` using a dict comprehension that returns a dictionary where keys are integers from 1 to `n` and values are their squares. Example: `squares_dict(5)` → `{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}`.

def squares_dict(n):
    pass


print(squares_dict(5))
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
Solution
def squares_dict(n):
    return {i: i ** 2 for i in range(1, n + 1)}


print(squares_dict(5))
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
06

Filter by Value

#

Write a function `filter_dict(d, min_value)` that returns a new dictionary containing only the key-value pairs where the value is greater than or equal to `min_value`. Example: `filter_dict({"a": 5, "b": 1, "c": 8, "d": 3}, 4)` → `{"a": 5, "c": 8}`.

def filter_dict(d, min_value):
    pass


print(filter_dict({"a": 5, "b": 1, "c": 8, "d": 3}, 4))
# {"a": 5, "c": 8}
Solution
def filter_dict(d, min_value):
    return {k: v for k, v in d.items() if v >= min_value}


print(filter_dict({"a": 5, "b": 1, "c": 8, "d": 3}, 4))
# {"a": 5, "c": 8}
07

Invert Dictionary

#

Write a function `invert(d)` that swaps keys and values in a dictionary and returns the new inverted dict. Assume all values are unique and hashable. Example: `invert({"a": 1, "b": 2, "c": 3})` → `{1: "a", 2: "b", 3: "c"}`.

def invert(d):
    pass


print(invert({"a": 1, "b": 2, "c": 3}))
# {1: "a", 2: "b", 3: "c"}
Solution
def invert(d):
    return {v: k for k, v in d.items()}


print(invert({"a": 1, "b": 2, "c": 3}))
# {1: "a", 2: "b", 3: "c"}
08

Group by First Letter

#

Write a function `group_by_letter(words)` that returns a dictionary where each key is a letter and the value is a sorted list of words starting with that letter. Example: `group_by_letter(["apple", "ant", "banana", "bear"])` → `{"a": ["ant", "apple"], "b": ["banana", "bear"]}`.

def group_by_letter(words):
    pass


print(group_by_letter(["apple", "ant", "banana", "bear"]))
# {"a": ["ant", "apple"], "b": ["banana", "bear"]}
Solution
def group_by_letter(words):
    result = {}
    for word in words:
        key = word[0]
        result.setdefault(key, []).append(word)
    for key in result:
        result[key].sort()
    return result


print(group_by_letter(["apple", "ant", "banana", "bear"]))
# {"a": ["ant", "apple"], "b": ["banana", "bear"]}
09

Nested Safe Access

#

Write a function `deep_get(data, *keys)` that safely accesses nested dictionary values using a chain of keys. Return `None` if any key is missing. Example: `deep_get({"user": {"address": {"city": "Kyiv"}}}, "user", "address", "city")` → `"Kyiv"`, `deep_get({"user": {}}, "user", "address", "city")` → `None`.

def deep_get(data, *keys):
    pass


user = {"user": {"address": {"city": "Kyiv"}}}
print(deep_get(user, "user", "address", "city"))   # Kyiv
print(deep_get(user, "user", "phone"))              # None
Solution
def deep_get(data, *keys):
    for key in keys:
        if not isinstance(data, dict):
            return None
        data = data.get(key)
    return data


user = {"user": {"address": {"city": "Kyiv"}}}
print(deep_get(user, "user", "address", "city"))   # Kyiv
print(deep_get(user, "user", "phone"))              # None
10

Dict from Two Lists

#

Write a function `zip_to_dict(keys, values)` that creates a dictionary from two lists of equal length. If the lists have different lengths, raise a `ValueError` with message `"Lists must have the same length"`. Example: `zip_to_dict(["a", "b", "c"], [1, 2, 3])` → `{"a": 1, "b": 2, "c": 3}`.

def zip_to_dict(keys, values):
    pass


print(zip_to_dict(["a", "b", "c"], [1, 2, 3]))
# {"a": 1, "b": 2, "c": 3}
zip_to_dict(["x", "y"], [1, 2, 3])  # raises ValueError
Solution
def zip_to_dict(keys, values):
    if len(keys) != len(values):
        raise ValueError("Lists must have the same length")
    return dict(zip(keys, values))


print(zip_to_dict(["a", "b", "c"], [1, 2, 3]))
# {"a": 1, "b": 2, "c": 3}
try:
    zip_to_dict(["x", "y"], [1, 2, 3])
except ValueError as e:
    print(e)