GGistDev

Dictionaries in Python

Dictionaries map keys to values with fast average lookups.

Creating dicts

Literal, constructor, and from pairs. fromkeys sets the same default object for each key (beware mutability).

empty = {}
conf = {"debug": False, "level": "info"}
from_pairs = dict([("a", 1), ("b", 2)])
from_keys = dict.fromkeys(["a", "b"], 0)

Access and presence

[] raises KeyError when missing; get returns a default; in checks keys.

v = conf["debug"]
v = conf.get("missing", 0)
exists = "level" in conf

Prefer get when a missing key is expected.

Insert, update, delete

Assign, update, setdefault, and pop.

conf["path"] = "/tmp"
conf.update({"level": "warn"})
conf.setdefault("retries", 0)     # initialize if missing
last = conf.pop("path", None)      # default if missing

setdefault returns the existing/new value and avoids a second lookup.

Iteration and views

Iterate keys/values/items; views reflect live changes.

for k in conf: ...          # keys
for v in conf.values(): ...
for k, v in conf.items(): ...

Unpack items when transforming.

upper = {k.upper(): v for k, v in conf.items()}

Comprehensions and merging

Build dicts concisely; merge with | (3.9+) and update with |=.

squares = {n: n*n for n in range(5)}
merged = {"a": 1} | {"b": 2}
conf |= {"level": "error"}

Copying and nested dicts

Shallow vs deep copy.

import copy
shallow = conf.copy()
deep = copy.deepcopy({"a": {"b": 1}})

defaultdict and Counter

Convenient counting and auto‑initialization.

from collections import defaultdict, Counter
counts = defaultdict(int)
for w in ["a","b","a"]:
    counts[w] += 1

freq = Counter(["a","b","a"])  # Counter({'a': 2, 'b': 1})

Pitfalls and tips

  • Keys must be hashable (immutable) types
  • Don’t mutate dict while iterating; iterate over list(conf.items()) if removing
  • Using mutable default for fromkeys shares the same object; prefer comprehensions
  • For ordered operations, Python 3.7+ preserves insertion order; use reversed(d) to iterate reversed keys

Performance notes

  • Dict lookups/updates are amortized O(1); prefer dicts for indexing by keys
  • For many small merges, dict.update is efficient and avoids creating intermediates

Summary

  • Dicts provide flexible key→value storage and fast lookups
  • Prefer get, setdefault, comprehensions, and |/|= for clarity; use defaultdict/Counter for counting and grouping