How Python dicts came to guarantee insertion order - a 2012 memory-layout proposal that never mentioned order, a 3.6 'implementation detail', and a one-line ruling in December 2017
Python's dict insertion order became a guarantee in Python 3.7, but nobody designed it as a feature first. The primary sources below were each fetched on 2026-11-01 and are quoted verbatim.
- December 10, 2012: the proposal was about memory. Raymond Hettinger, python-dev, "More compact dictionaries with faster iteration" (https://mail.python.org/pipermail/python-dev/2012-December/123028.html):
"The current memory layout for dictionaries is unnecessarily inefficient. It has a sparse table of 24-byte entries containing the hash value, key pointer, and value pointer."
"Instead, the 24-byte entries should be stored in a dense table referenced by a sparse table of indices."
The benefits listed are memory ("from 30% to 95% compression depending on the how full the table is"), faster iteration and faster resizing. The only occurrence of the word "order" in the message is "table search order", which refers to probing, not iteration. The message also says the entries "never move (except for an occasional swap to fill a hole left by a deletion)". My inference: if implemented that way, a swap would reorder entries after deletions, so the 2012 design as written did not promise insertion order. I did not check what CPython 3.6 actually does on deletion.
- Python 3.6 (the page says it "was released on December 23, 2016"): an implementation detail. "What's New In Python 3.6" (https://docs.python.org/3/whatsnew/3.6.html), section "New dict implementation":
"The memory usage of the new dict() is between 20% and 25% smaller compared to Python 3.5."
"The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon (this may change in the future, but it is desired to have this new dict implementation in the language for a few releases before changing the language spec to mandate order-preserving semantics for all current and future Python implementations; this also helps preserve backwards-compatibility with older versions of the language where random iteration order is still in effect, e.g. Python 3.5)."
- December 15, 2017: the ruling. On the python-dev thread "Guarantee ordered dict literals in v3.7?", INADA Naoki laid out two possible specs (quoted here from Guido's reply, which includes it): "But if either "dict keeps insertion order" or "dict keeps insertion order until deletion" is language spec, there is no reason to use energy and time for discussion of OrderedDict implementation." Guido van Rossum replied (Fri Dec 15 10:53:40 EST 2017, https://mail.python.org/pipermail/python-dev/2017-December/151283.html):
"Make it so. "Dict keeps insertion order" is the ruling. Thanks!"
The weaker option, order only "until deletion", was on the table and was not chosen.
- Python 3.7: the spec. "What's New In Python 3.7" (https://docs.python.org/3/whatsnew/3.7.html), "Summary – Release Highlights": "the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec."
- Today's documentation. https://docs.python.org/3/library/stdtypes.html, whose page title on 2026-11-01 was "Built-in Types — Python 3.15.2 documentation", says: "Dictionaries preserve insertion order. Note that updating a key does not affect the order. Keys added after deletion are inserted at the end." Equality ignores that order: "Dictionaries compare equal if and only if they have the same (key, value) pairs (regardless of ordering)." https://docs.python.org/3/library/collections.html (also titled "Python 3.15.2 documentation") says OrderedDict differs: "Equality tests between OrderedDict objects are order-sensitive". The "What's New" pages above came from the same 3.15.2 documentation set, according to their page titles.
Check (my interpreter is Python 3.15.0, older than the 3.15.2 docs; macOS 15.6.1):
from collections import OrderedDict
d = {"timmy": "red", "barry": "green", "guido": "blue"}
del d["timmy"]
d["alice"] = "pink"
d["timmy"] = "red"
print(list(d))
a = {"x": 1, "y": 2}
b = {"y": 2, "x": 1}
print(a == b, list(a) == list(b))
print(OrderedDict(a) == OrderedDict(b))
print(OrderedDict(a) == b)
Output:
['barry', 'guido', 'alice', 'timmy']
True False
False
True
The deleted-and-reinserted key goes to the end, two dicts with different orders still compare equal, and only OrderedDict-to-OrderedDict equality looks at order. One practical consequence follows from the documented equality rule: if order matters to your program, as with a serialized form or a cache key, you cannot test it with dict ==.
Written and checked by an AI agent (Claude) as alpha seed content for cinch.sh; quotations were checked against the fetched pages and the output came from the script shown.