Skip to Content
Dictionaries

Dictionaries

Dictionaries store key–value pairs. Keys must be hashable; values can be any type. As of Python 3.7, dictionaries preserve insertion order (Python 3.6 and earlier: unordered).

Creating Dictionaries

Use curly braces {} or dict(). Empty dictionary: {}.

data = {"a": 2, "b": 4, "c": 6} built = dict(a=2, b=4, c=6) # keyword args; keys become strings built = dict([("a", 2), ("b", 4), ("c", 6)]) # from list of pairs empty = {}

dict() keyword args: Keys must be valid identifiers (no spaces, no quotes). dict(2=4) is invalid; use {"2": 4}.

Length: Use len(d) for the number of key–value pairs.

Type: type(data)<class 'dict'>.

Truthiness: An empty dictionary {} is falsy; a non-empty dictionary is truthy. Use if d: for “at least one pair” and if not d: for “no keys”.

Build from two sequences: Use zip() to pair keys and values, then pass the result to dict(). The shorter sequence limits the number of pairs.

labels = ["x", "y", "z"] vals = [2, 4, 6] mapping = dict(zip(labels, vals)) # {"x": 2, "y": 4, "z": 6}

Dictionary Properties

  • Ordered (Python 3.7+) - insertion order is preserved; iteration order is stable.
  • Changeable - add, change, or remove items after creation.
  • Unique keys - duplicate keys overwrite earlier values; only the last wins.
data = {"a": 2, "b": 4, "c": 6, "b": 8} # "b": 4 overwritten print(data) # {"a": 2, "b": 8, "c": 6}

Mixed value types: Values can be strings, numbers, lists, dictionaries, or any type. Keys must be hashable (strings, numbers, tuples of hashables).

Dictionary Methods

MethodDescription
get(key, default)Return value for key; default if missing (no KeyError)
keys()View of keys
values()View of values
items()View of (key, value) pairs
fromkeys(seq, value)New dictionary with keys from seq, values value (default None)
setdefault(key, default)Return value; if key missing, insert default and return it
update(other)Update dictionary with key–value pairs from other
pop(key, default)Remove key, return value; KeyError if missing (or default)
popitem()Remove and return last inserted (key, value)
clear()Remove all elements from the dictionary
copy()Return a copy of the dictionary (shallow)

Access Dictionary Items

Bracket notation: d[key] - raises KeyError if key is missing.

get(key, default) - returns default (or None) if key is missing; no exception.

data = {"a": 2, "b": 4, "c": 6} data["b"] # 4 data["x"] # KeyError data.get("b") # 4 data.get("x") # None data.get("x", 0) # 0 - custom default

keys(), values(), items()

These return view objects - they reflect the current state of the dictionary. Changes to the dictionary are visible in the view; the view is not a snapshot.

data = {"a": 2, "b": 4, "c": 6} k = data.keys() print(list(k)) # ["a", "b", "c"] data["d"] = 8 print(list(k)) # ["a", "b", "c", "d"] - view updated

keys() - view of keys. values() - view of values. items() - view of (key, value) tuples.

To get a snapshot (list), wrap in list(): list(d.keys()).

fromkeys(seq, value) - create a dictionary with keys from seq; all values value (default None).

dict.fromkeys(["a", "b", "c"]) # {"a": None, "b": None, "c": None} dict.fromkeys(["a", "b", "c"], 0) # {"a": 0, "b": 0, "c": 0}

setdefault(key, default) - if key exists, return its value. If not, set d[key] = default and return default. Useful for “get or create”.

data = {"a": 2, "b": 4} data.setdefault("c", 6) # 6; data["c"] = 6 data.setdefault("a", 0) # 2 - key exists, unchanged

Check if Key Exists

Use in and not in on the dictionary. Membership tests keys only, not values - so a value like 2 is not “in” the dictionary unless it is a key.

data = {"a": 2, "b": 4, "c": 6} "b" in data # True - "b" is a key "x" not in data # True 2 in data # False - 2 is a value, not a key

Reversing a Dictionary

To get a new dictionary with keys in reverse insertion order, use dict(reversed(d.items())) (Python 3.8+). For older Python, use dict(reversed(list(d.items()))).

data = {"a": 2, "b": 4, "c": 6} rev = dict(reversed(data.items())) # {"c": 6, "b": 4, "a": 2}

Unpacking Dictionaries

In a dictionary literal, **other unpacks the key–value pairs of other into the new dictionary. Combine with extra keys to override or add entries. Useful for merging or applying overrides without mutating the original.

base = {"a": 2, "b": 4, "c": 6} extended = {**base, "c": 8, "d": 10} # c overwritten, d added # {"a": 2, "b": 4, "c": 8, "d": 10}

Add Dictionary Items

Assign to a new key to add an item.

data = {"a": 2, "b": 4} data["c"] = 6 print(data) # {"a": 2, "b": 4, "c": 6}

Change Dictionary Items

Assign to a key to change its value.

data = {"a": 2, "b": 4, "c": 6} data["b"] = 8 print(data) # {"a": 2, "b": 8, "c": 6}

Update Dictionary

update(other) - merge another dictionary or iterable of (key, value) pairs into the existing dictionary. Existing keys are overwritten; new keys are added. Accepts keyword args.

data = {"a": 2, "b": 4} data.update({"b": 8, "c": 6}) # dictionary: b overwritten, c added data.update([("d", 8), ("e", 10)]) # iterable of pairs data.update(f=12) # keyword: "f": 12 print(data) # {"a": 2, "b": 8, "c": 6, "d": 8, "e": 10, "f": 12}

Remove Dictionary Items

MethodBehavior
pop(key)Remove key, return value; KeyError if missing
pop(key, default)Remove key, return value; return default if missing
popitem()Remove and return last (key, value); Python 3.7+ LIFO; pre-Python 3.7: arbitrary
del d[key]Remove item; KeyError if missing
del dDelete the variable; name undefined; access raises NameError
clear()Remove all items; dictionary becomes {}
data = {"a": 2, "b": 4, "c": 6} data.pop("b") # 4; data = {"a": 2, "c": 6} data.pop("x", 0) # 0 - key missing, default returned data.popitem() # ("c", 6) - last inserted in Python 3.7+ del data["a"] # remove "a" data.clear() # {}

popitem() and version: In Python 3.7+, removes the last inserted item (LIFO). In Python 3.6 and earlier, removes an arbitrary item.

Loop Dictionaries

By keys (default): for k in d iterates over keys.

By values: for v in d.values().

By keys and values: for k, v in d.items().

data = {"a": 2, "b": 4, "c": 6} for k in data: print(k, data[k]) # a 2, b 4, c 6 for k in data.keys(): print(k) # a, b, c - explicit keys for v in data.values(): print(v) # 2, 4, 6 for k, v in data.items(): print(k, v) # a 2, b 4, c 6

Loop in reverse: To iterate in reverse insertion order, use reversed() on the dictionary or on d.items() (Python 3.8+). On older Python, use reversed(list(d.items())).

data = {"a": 2, "b": 4, "c": 6} for k in reversed(data): print(k, data[k]) # c 6, b 4, a 2 for k, v in reversed(data.items()): print(k, v) # c 6, b 4, a 2

Dictionary Comprehension

Build a dictionary from an iterable with {key_expr: value_expr for ... in ...}. You can add an if to filter. Keys and values can be computed from the loop variable.

squares = {n: n * n for n in [2, 4, 6, 8]} # {2: 4, 4: 16, 6: 36, 8: 64} upper = {k.upper(): v for k, v in [("a", 2), ("b", 4)]} # {"A": 2, "B": 4} evens_only = {x: x * 2 for x in range(6) if x % 2 == 0} # {0: 0, 2: 4, 4: 8}

Copy Dictionaries

d2 = d1 creates a reference, not a copy. Changes to d1 affect d2.

Shallow copy: Use copy() or dict(d).

original = {"a": 2, "b": 4, "c": 6} ref = original # reference - same object copy = original.copy() # shallow copy also_copy = dict(original) original["a"] = 0 # ref["a"] is 0; copy["a"] is still 2

Shallow vs deep: copy() and dict() copy the top level only. Nested dictionaries or lists are shared. Use copy.deepcopy() for full copies.

import copy original = {"a": {"x": 2, "y": 4}, "b": {"x": 6, "y": 8}} shallow = original.copy() shallow["a"]["x"] = 0 # original["a"]["x"] is also 0 - shared deep = copy.deepcopy(original) deep["a"]["x"] = 0 # original unchanged - independent

Sort Dictionaries

Dictionaries have no sort() method. To iterate in sorted order, use sorted() on keys or items().

data = {"c": 6, "a": 2, "b": 4} for k in sorted(data): print(k, data[k]) # a 2, b 4, c 6 for k, v in sorted(data.items()): print(k, v) # a 2, b 4, c 6 for k, v in sorted(data.items(), key=lambda p: p[1]): print(k, v) # a 2, b 4, c 6 - sort by value

New dictionary from sorted items: dict(sorted(data.items())) - creates a dictionary with keys in sorted order.

Nested Dictionaries

Values can be dictionaries. Access with chained brackets.

nested = { "p1": {"x": 2, "y": 4}, "p2": {"x": 6, "y": 8}, } nested["p1"]["x"] # 2 nested["p2"]["y"] # 8

Build from separate dictionaries:

inner1 = {"x": 2, "y": 4} inner2 = {"x": 6, "y": 8} outer = {"p1": inner1, "p2": inner2}

Loop nested dictionaries:

for key, obj in nested.items(): print(key) for k, v in obj.items(): print(f" {k}: {v}")

Reversing Key–Value Pairs

When keys and values are unique, you can build a dictionary that maps each value back to its key: {v: k for k, v in d.items()}. Useful for reverse lookups (e.g. “which key has this value?”).

code_to_name = {"uk": "United Kingdom", "de": "Germany", "fr": "France"} name_to_code = {v: k for k, v in code_to_name.items()} name_to_code["Germany"] # "de"

If values are not unique, later keys overwrite earlier ones; only one key per value remains.

Dictionary vs Other Collections

CollectionOrderIndexingKey–valueUse when
dictionaryYesBy key onlyYesLookup by name or id; config; mapping one value to another
listYesBy positionNoSequence; order matters; duplicates allowed
tupleYesBy positionNoImmutable sequence; fixed layout; hashable
setNoNoNoUnique elements; fast membership; set operations

Note: Dictionary order is guaranteed from Python 3.7 onward (insertion order). In Python 3.6 and earlier, iteration order was not guaranteed.

Choose a dictionary when you need to associate keys with values and look them up by key. Use a list or tuple when position matters; use a set when you only care about membership or uniqueness.

Common Use Cases

  • Config or options: Store names and values (e.g. {"timeout": 30, "retries": 2}). Override with {**defaults, **overrides}.
  • Counting: Track how many times something appears. Use counts[key] = counts.get(key, 0) + 1 or group with setdefault(key, []).append(item).
  • Grouping: Collect items by a key (e.g. group people by role). groups.setdefault(role, []).append(person) keeps a list per role.
  • Lookup tables: Map IDs or codes to names, or the reverse. Build from two lists with dict(zip(ids, names)) or invert with a comprehension when values are unique.

Tricky Behaviors

Creating - Empty dictionary

{} is falsy; use if not d: for “no keys”. No literal for “empty” other than {}.

Creating - dict() keyword args

Keys must be valid identifiers (no spaces, no 2=4); use {"2": 4} for numeric-like keys.

Creating - dict(zip(...))

Length is the shorter of the two iterables; extra elements in either are ignored.

Dictionary Properties - Duplicate keys

Later value overwrites earlier; no error; only the last value is kept.

Access - d[key] vs d.get(key)

[] raises KeyError if missing; get() returns None or default.

keys(), values(), items()

Return views, not lists; reflect live changes; modifying dictionary size while iterating can raise RuntimeError.

Check if Key Exists - in

Membership tests keys only; a value that is not a key (e.g. 2 in {"a": 2}) is False.

Reversing a Dictionary

reversed(d) and reversed(d.items()) require Python 3.8+; on older versions use reversed(list(d.items())).

Unpacking (dictionary literal)

Using **other in a dictionary literal builds a new dictionary; does not mutate other. Later keys overwrite.

Update - update() return value

update() mutates the dictionary and returns None; do not assign the result and expect a new dictionary.

Remove - popitem()

Python 3.7+: LIFO (last inserted); pre-Python 3.7: arbitrary item.

Remove - del d

Deletes the variable; the name is gone; access raises NameError.

Copy - d2 = d1

Reference, not copy; changes to one affect the other. Use copy() or dict(d) for a shallow copy.

Sort

Dictionaries have no sort() method; use sorted(d) or sorted(d.items()) for a new ordering.

Nested - missing key

d["a"]["b"] raises KeyError if "a" is missing; use d.get("a", {}).get("b", default) for safe access.

Reversing Key–Value

If values are not unique, later keys overwrite earlier; the inverse dictionary has only one key per value.

Interview Questions

How do you create an empty dictionary? What about truthiness?

Use {}. An empty dictionary is falsy; use if not d: for “no keys” and if d: for “at least one pair”.

How do you build a dictionary from two lists (keys and values)?

Use dict(zip(keys_list, values_list)). Pairs the first key with the first value, and so on. The length of the result is the length of the shorter list.

When would you use dict.fromkeys()?

When you need a dictionary with the same value for many keys (e.g. default 0 or None). dict.fromkeys(keys, value) is shorter than a loop or comprehension when every value is the same.

Why must dictionary keys be hashable?

Dictionaries use a hash table; keys are hashed for O(1) lookup. Mutable types (lists, dictionaries) are unhashable and cannot be keys.

Are dictionaries ordered?

Yes, since Python 3.7 (insertion order). In Python 3.6 it was a CPython implementation detail; before that, unordered. Order matters for predictable iteration and popitem() LIFO behavior.

What is the time complexity of dictionary get, set, and delete?

O(1) average for get, set, and delete. Iteration is O(n).

When should you use d[key] vs d.get(key)?

Use get() when the key may be missing and you want a default or None. Use [] when the key must exist; let KeyError surface bugs.

Are keys(), values(), items() lists?

No - they return view objects. Views reflect live changes to the dictionary. Modifying the dictionary while iterating over a view can raise RuntimeError if the dictionary size changes. For a safe snapshot, use list(d.items()).

Does in check keys or values?

Keys only. value in d is True only if that value is a key; so 2 in {"a": 2} is False.

When should you use setdefault() vs get() + assign?

Use setdefault() when you need get-or-create and then mutate in place (e.g. groups.setdefault(category, []).append(item)). Use get() when you only need the value.

How do you iterate a dictionary in reverse insertion order?

Use reversed(d) or reversed(d.items()) (Python 3.8+). On older Python, use reversed(list(d.items())).

How do you build a new dictionary with keys in reverse insertion order?

Use dict(reversed(d.items())) (Python 3.8+). For older Python, use dict(reversed(list(d.items()))). This creates a new dictionary; the original is unchanged.

What does {**d1, **d2} do? Does it mutate either dictionary?

It builds a new dictionary by unpacking d1 and then d2. Keys from d2 overwrite same-named keys from d1. It does not mutate either dictionary.

How do you merge two dictionaries without mutating either?

Use {**d1, **d2} or d1 | d2 (Python 3.9+). To mutate one of them, use d1.update(d2).

What does update() return?

None. It mutates the dictionary in place. Do not assign the result; use {**d1, **d2} or d1 | d2 (Python 3.9+) if you need a new dictionary.

pop() vs del vs popitem() - when to use each?

pop(key) returns the value; use when you need it. del d[key] removes without returning. popitem() removes the last inserted item (Python 3.7+); useful for LIFO processing or draining a dictionary.

Does for k in d differ from for k in d.keys()?

No - both iterate over keys. d.keys() is explicit; for k in d is idiomatic and slightly shorter. Same iteration order.

When would you use a dictionary comprehension instead of a loop?

When you are building a new dictionary from an iterable in one expression (e.g. {k: v * 2 for k, v in d.items()} or {x: x ** 2 for x in range(4)}). Keeps the code short and avoids creating an empty dictionary and updating it in a loop.

When does shallow vs deep copy matter for dictionaries?

When values are mutable (lists, dictionaries). Changing copy["nested"]["x"] affects the original; copy["a"] = 0 does not. Use copy.deepcopy() for full copies.

How do you sort a dictionary by value?

sorted(d.items(), key=lambda p: p[1]) - sorts by value. To get a new dictionary: dict(sorted(d.items(), key=lambda p: p[1])).

How do you safely access a nested dictionary value?

d.get("a", {}).get("b", default) - chain get() with an empty dictionary default so a missing key does not raise KeyError.

How do you swap keys and values? When is it safe?

Use {v: k for k, v in d.items()}. Safe only when values are unique; otherwise later keys overwrite earlier ones and you keep a single key per value.

When should you choose a dictionary over a list or set?

Use a dictionary when you need to look up a value by a key (name, ID, or code). Use a list when order and position matter; use a set when you only need unique elements or fast membership and no mapping.

How do you count occurrences or group items with a dictionary?

Counting: counts[key] = counts.get(key, 0) + 1. Grouping: groups.setdefault(key, []).append(item).

Last updated on