Python developers have been asking for an immutable dictionary type for years. The use cases are obvious — hashable dicts for caching keys, frozen configuration objects that can’t be accidentally mutated, and safer default arguments that don’t share state across function calls. But every proposal to add one has stalled, been rejected, or faded into the PEP graveyard.
PEP 814, authored by core developer Victor Stinner and Donghee Na, looks like it might finally break the streak.
What frozendict Actually Is
A frozendict is a dictionary that can’t be modified after creation. Once you create one, you can look up keys, iterate over items, and hash it — but you can’t add, remove, or change entries. In type annotation terms, it’s a Mapping rather than a MutableMapping (Victor Stinner blog, July 2026).
The key design decisions in PEP 814:
Insertion order is preserved, just like regular dicts since Python 3.7. This means iterating over a frozendict produces items in the order they were added.
Comparison and hashing are order-independent. Two frozendicts with the same key-value pairs compare equal and produce the same hash regardless of insertion order. This matches dict’s equality semantics and makes frozendicts safe to use as dictionary keys or set elements.
The API is intentionally smaller than dict’s. frozendict has fewer methods because mutating methods like update(), pop(), and clear() don’t apply. You get the read-only operations — __getitem__, get(), keys(), values(), items(), __contains__, __iter__, __len__, and __hash__.
Why It Took Over a Decade
The first serious attempt was PEP 416 in 2012, which proposed a frozendict type. It was rejected — the core team at the time argued that the use cases were better served by existing tools like types.MappingProxyType or third-party libraries.
PEP 603, proposed as frozenmap, generated 215 messages of discussion but was never formally submitted to the Steering Council. One issue was that frozenmap didn’t preserve insertion order, which made it a poor fit for Python’s post-3.7 dict semantics.
Stinner and Na’s PEP 814 addresses the rejection reasons directly: it preserves order, it’s a proper built-in type rather than a stdlib addition, and the rationale is anchored in concrete use cases that have only grown more common — caching, configuration management, and functional programming patterns that treat data as immutable by default.
What Changes in Practice
If PEP 814 is accepted and lands in Python 3.14 (or 3.15), the most immediate impact will be on code that currently uses workarounds. Today, if you want a hashable key-value structure, your options are:
tuple(sorted(d.items()))— works but is ugly and slowtypes.MappingProxyType— creates a read-only view but doesn’t support hashing- The
immutablespackage from PyPI — a solid third-party solution but adds a dependency
A built-in frozendict eliminates all three tradeoffs. You get a native, hashable, ordered, immutable mapping with no dependencies and predictable performance.
For web frameworks, this matters in request context objects and configuration. For data pipelines, it matters in cache keys and intermediate representations. For library authors, it matters in public APIs where you want to return data that callers can read but can’t accidentally corrupt.
The PEP is still under discussion, but Stinner’s track record as a core developer — he maintains substantial portions of CPython’s internals — gives this proposal more momentum than its predecessors ever had. If you’ve ever wrapped tuple(sorted(d.items())) and thought “there has to be a better way,” keep an eye on PEP 814.
Discussion
Leave a comment
No comments yet
Be the first to start the conversation.