Dict Ordering Guarantees in Python 3.7+
Think of a modern Python dictionary's order as a chronological log of key insertions. Updating a key doesn't change its log entry's position, but deleting an entry removes it from the log, and re-adding it appends a new entry to the end of the log.
The Setup
You are writing a metadata serialization module that exports key-value configurations to flat arrays, expecting the payload order to remain identical to the definition order. An automated script updates these entries dynamically over time.
What Does This Print?
config = {"a": 1, "b": 2, "c": 3}
# Update configurations
config["a"] = 100
del config["b"]
config["b"] = 200
print("Keys ordered after modification:", list(config.keys()))
b retain its original second slot or shift to the end?
The Output
The key order is ['a', 'c', 'b']. Re-adding deleted keys places them at the end of the insertion queue, while updating an existing key maintains its relative position.
Why Python Does This
Since Python 3.6 (and guaranteed in 3.7+), dicts use a split-table representation designed by Raymond Hettinger. Instead of a sparse array containing pointers to keys and values, CPython utilizes an integer array (indices) and a dense array (entries) holding the actual hash, key, and value in order of arrival. Updating a key updates its value inline in the dense array. Deleting a key removes its reference and marks the index slot as dummy, and adding it back appends it to the end of the dense array, altering the relative iteration order.
The Fix
config = {"a": 1, "b": 2, "c": 3}
config["a"] = 100
# Update b's value in place — no delete, so the key retains its original position
config["b"] = 200
print("Keys ordered after modification:", list(config.keys()))
# Output: ['a', 'b', 'c'] — b stays in slot 2
Updating a key in place (config["b"] = 200) modifies the value stored in the existing dense-array entry without touching the indices array. The key's slot in the insertion sequence never changes. Deleting and re-inserting, by contrast, removes the entry from the dense array and appends a new one at the end, reordering the key.
How This Fails in Real Systems
A dynamic API gateway payload signed outgoing requests using a SHA256 signature generated over dictionary keys. When updates were deployed, some key modifications caused unexpected reordering, breaking the deterministic hashing mechanism and leading to 5% of webhooks being rejected.