Skip to main content

python-frozendict

A back-port of Python 3.15's frozendict builtin for older Python versions.

On Python 3.15+, you can write:

SETTINGS = frozendict({"debug": True, "level": 3})

This package provides the same behaviour on every supported Python version (3.8+) via a small, focused, dependency-free implementation.

Why?

A frozendict is an immutable, hashable mapping. It is useful wherever you would reach for dict but want a value that:

  • cannot be mutated by accident (or on purpose);
  • is hashable and therefore usable as a dict key or a set member;
  • serves as a clear, self-documenting signal that the data is fixed.
from frozendict import frozendict

USER_ROLES = frozendict({
    "alice": "admin",
    "bob": "editor",
})

# `USER_ROLES` is a valid dict key, set member, function default, etc.
cache = {USER_ROLES: "loaded"}

# Attempting to mutate it raises `TypeError`:
USER_ROLES["carol"] = "viewer"
# -> TypeError: 'frozendict' object does not support item assignment

Installation

pip install python-frozendict

Usage

Basic construction

from frozendict import frozendict

empty = frozendict()
from_dict = frozendict({"a": 1, "b": 2})
from_pairs = frozendict([("a", 1), ("b", 2)])
from_mapping = frozendict(some_Mapping_instance)
copy_of = frozendict(from_dict)  # new object, same content

The constructor accepts at most one positional argument (a dict, a Mapping, another frozendict, or any iterable of pairs). Keyword arguments are rejected, mirroring dict itself.

Reading

frozendict supports the full read-only mapping interface:

fd = frozendict({"a": 1, "b": 2, "c": 3})

fd["a"]              # 1
len(fd)              # 3
"a" in fd            # True
list(fd)             # ["a", "b", "c"]
list(fd.keys())      # ["a", "b", "c"]
list(fd.values())    # [1, 2, 3]
list(fd.items())     # [("a", 1), ("b", 2), ("c", 3)]
fd.get("z", 0)       # 0
list(reversed(fd))   # ["c", "b", "a"]

It is registered as a collections.abc.Mapping so it works with any function that accepts a generic mapping.

Hashing and equality

frozendict is hashable, if all of its values are hashable. Two frozendict objects with the same content compare equal and have the same hash, independent of insertion order:

a = frozendict({"a": 1, "b": 2})
b = frozendict({"b": 2, "a": 1})

a == b     # True
hash(a) == hash(b)   # True

A frozendict compares equal to a dict with the same content, and is usable as a dict key or a set element:

fd = frozendict({"a": 1})
{fd: "value"}            # {frozendict({'a': 1}): "value"}
{fd, frozendict({"a": 1})}   # a single-element set: {frozendict({'a': 1})}

If any value is unhashable, calling hash(fd) raises TypeError — this mirrors the behaviour of tuple.

Merging with |

The | operator returns a new frozendict; the operands are not mutated:

a = frozendict({"a": 1, "b": 2})
b = frozendict({"b": 99, "c": 3})

a | b           # frozendict({'a': 1, 'b': 99, 'c': 3})
{"x": 0} | a    # frozendict({'x': 0, 'a': 1, 'b': 2})

On key conflicts, the right-hand side wins — same as the built-in dict merge.

Immutability

Any attempt to mutate a frozendict raises TypeError:

fd = frozendict({"a": 1})
fd["b"] = 2        # TypeError
del fd["a"]        # TypeError
fd.clear()         # TypeError
fd.update({"b": 2})  # TypeError
fd.setdefault("b", 2)  # TypeError
fd.pop("a")        # TypeError
fd.popitem()       # TypeError

Copy and pickle

copy.copy(fd), copy.deepcopy(fd), and fd.copy() all return the same object (there is no need to copy an immutable value).

Pickling and unpickling preserves content but not identity:

import pickle
fd = frozendict({"a": 1, "b": 2})
restored = pickle.loads(pickle.dumps(fd))
restored == fd          # True
restored is fd          # False

Subclassing

Subclassing is not supported. Both class Sub(frozendict): pass and type("Sub", (frozendict,), {}) raise TypeError.

API

frozendict(*[mapping_or_pairs]*)

Construct a new frozendict. At most one positional argument is accepted:

Argument Behaviour
omitted empty frozendict
dict shallow copy of the dict
frozendict shallow copy
collections.abc.Mapping shallow copy via dict(mapping)
iterable of (key, value) equivalent to dict(iterable)

Keyword arguments are rejected. Passing more than one positional argument raises TypeError.

Methods and operators

Member Description
fd[key] raise KeyError if missing
key in fd membership test
len(fd) number of items
iter(fd) iterate over keys (insertion order)
reversed(fd) iterate over keys in reverse
fd.keys() / fd.values() / fd.items() mapping views (read-only)
fd.get(key, default=None) safe lookup
fd.copy() returns fd (immutable)
fd == other content-based equality
hash(fd) content-based hash (cached)
fd | other / other | fd merge, returns a new frozendict
repr(fd) / str(fd) "frozendict({...})"
bool(fd) False for empty, True otherwise
pickle.dumps/loads(fd) content preserved
copy.copy(fd) / copy.deepcopy(fd) both return fd
dict(fd) convert to dict

Forbidden operations

These all raise TypeError:

Attempted Error message
fd[key] = value 'frozendict' object does not support item assignment
del fd[key] 'frozendict' object does not support item deletion
fd.clear() 'frozendict' object does not support item assignment
fd.pop(...) 'frozendict' object does not support item deletion
fd.popitem() 'frozendict' object does not support item deletion
fd.setdefault(...) 'frozendict' object does not support item assignment
fd.update(...) 'frozendict' object does not support item assignment
class Sub(fd): subclassing frozendict is not supported
fd.foo = "bar" 'frozendict' object has no attribute 'foo'

Python 3.15+ native syntax

When you are running on Python 3.15+, frozendict is a true builtin. The package's own API still works identically, so you can use either:

# Native (Python 3.15+ only):
SETTINGS = frozendict({"debug": True})

# Cross-version equivalent via this package:
from frozendict import frozendict
SETTINGS = frozendict({"debug": True})

Compatibility

  • Python 3.8 through 3.15+ (uses collections.abc.Mapping; on 3.9+ uses modern union / merge syntax in the docs only).
  • No third-party dependencies — uses only the standard library.

Running the tests

python -m unittest test_frozendict.py -v

Retirement

This project will reach its end-of-life around October 1, 2031 — the official EOL date of Python 3.15 — and the exact timeline could be slightly delayed. We plan to ship the final stable release in November 2031. After this release, all support will cease and the repository will be officially archived, as this library is developed solely to bring frozendict compatibility to Python 3.15 and older versions.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_frozendict-0.1.0.tar.gz (14.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_frozendict-0.1.0-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file python_frozendict-0.1.0.tar.gz.

File metadata

  • Download URL: python_frozendict-0.1.0.tar.gz
  • Upload date:
  • Size: 14.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for python_frozendict-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b78395973abb05431b9333a651d0a02a71e500ec7546070e188f353c9c6f2103
MD5 51c742940ec2a15c077209eadeef038f
BLAKE2b-256 e0c46357cef668a77399fda43def63b22268a146b1be31ff06246c3d72170ecd

See more details on using hashes here.

File details

Details for the file python_frozendict-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for python_frozendict-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 08aa62fae8fc2606014f775a4af3d1094ddae7aefe747c169e8c40e259acc9eb
MD5 cb083722fe3a0eeaeda92bea4ebcb2a1
BLAKE2b-256 bb38ece18ac2625730152e060d0e8080991a7cd378fa13d69902c54076d58317

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page