dict Internals
Python dicts are hash tables — O(1) average-case get/set/delete, O(n) worst case (hash collisions).
A dict is a coat check room. You hand over your hashable ticket (key), and they instantly find your coat (value). Since Python 3.7, coats hang in the order they arrived.
As of Python 3.7+, dicts preserve insertion order (guaranteed by the language spec, not just CPython). O(1) average for get, set, delete, and in. Keys must be hashable (immutable). dict.get(key, default) avoids KeyError. dict comprehensions: {k: v for k, v in items}. Merging: {**a, **b} (Python 3.5+) or a | b (Python 3.9+).
CPython's dict uses open addressing with a compact table redesign (Python 3.6+). The hash table stores indices into a separate array of (hash, key, value) entries — this keeps insertion order while maintaining O(1) lookup. Load factor is ~2/3 — when 2/3 full, the table resizes (doubles). Hash collisions are handled by probing. The dict's memory layout is split-table for class __dict__ (shared key table across instances with the same attributes) vs combined-table for general dicts. Unhashable types (list, dict, set) can't be keys — they define __eq__ but not __hash__.
Python dicts are hash tables with O(1) average operations. They preserve insertion order since Python 3.7. Keys must be hashable — defining __eq__ without __hash__ makes a type unhashable. For counting, use Counter. For missing-key defaults, use defaultdict. For ordered operations like LRU cache, OrderedDict has move_to_end(). The dict resize happens at ~2/3 capacity — keep this in mind if you're pre-sizing a dict for performance.
Modifying a dict while iterating over it raises RuntimeError. Iterate over list(d.keys()) or list(d.items()) if you need to delete during iteration.