Dictionaries and Keyed State
A dict maps unique, hashable keys to values. It is mutable and preserves
insertion order, but that order is not sorted order.
counts = {"jpg": 10, "csv": 2}
counts["csv"] += 1
counts["txt"] = 4
Lookup contracts
Choose the operation that matches how absence should be handled:
required = config["region"] # KeyError if absent
optional = config.get("timeout", 30) # default if absent
if "token" in config: # membership checks keys
use(config["token"])
get cannot distinguish a missing key from a present key whose value equals the
default. Use membership testing or a private sentinel when that distinction
matters.
For accumulation, collections.defaultdict and collections.Counter often
state the intent better than repeated setdefault calls.
Keys and hashing
Keys must be hashable. Strings, numbers, and tuples of hashable values commonly qualify; lists and dictionaries do not. Objects that compare equal must have the same hash. Mutating data involved in equality or hashing after using an object as a key can make the mapping logically inconsistent.
Prefer domain identifiers with stable equality semantics. Do not use a mutable container merely because it can be wrapped in a custom hash implementation.
Iteration and views
for key in mapping:
...
for key, value in mapping.items():
...
keys = mapping.keys() # dynamic view, not a copied list
values = mapping.values()
Changing the dictionary's size while iterating over a view can raise an error or
skip intended work. Iterate over list(mapping.items()) when a snapshot is
needed.
Updating and merging
update mutates the receiver. The | operator creates a new dictionary. In
both cases, values on the right win when keys overlap.
effective = defaults | overrides
defaults.update(overrides)
These are shallow operations: nested mappings are replaced, not recursively merged. Define an explicit policy for deep configuration merging.
Lookup, insertion, and deletion are typically on average; they are not a hard worst-case constant-time guarantee. Iteration is .