Skip to content

API¤

xmmutablemap.ImmutableMap ¤

Bases: frozendict[K, V]

Immutable mapping that JAX understands as a PyTree.

A frozendict (PEP 814 <https://peps.python.org/pep-0814/>_ on Python 3.15+, a matching stand-in below that) registered as a JAX PyTree node. Everything a frozendict does, it does; the difference is that JAX traverses it as a container rather than treating it as an opaque leaf.

Parameters:

Name Type Description Default
*args Mapping[K, V] | Iterable[tuple[K, V]]

At most one positional argument, as for dict.

required
**kwargs V

Key-value pairs.

required

Examples:

>>> from xmmutablemap import ImmutableMap
>>> d = ImmutableMap(a=1, b=2)
>>> d
ImmutableMap({'a': 1, 'b': 2})

It is a frozendict, and compares equal to any equal mapping:

>>> from xmmutablemap import frozendict
>>> isinstance(d, frozendict)
True
>>> d == {"a": 1, "b": 2}
True

Being immutable, it is hashable, order-independently:

>>> hash(ImmutableMap(a=1, b=2)) == hash(ImmutableMap(b=2, a=1))
True

Unlike a plain frozendict, JAX sees the structure:

>>> import jax
>>> jax.tree.structure(d)
PyTreeDef(CustomNode(ImmutableMap[('a', 'b')], [*, *]))

__or__(other: Any) -> ImmutableMap[K, V] ¤

Merge with another mapping, keeping this type.

frozendict.__or__ hardcodes its result type, so a subclass would otherwise get a plain frozendict back.

Deliberately looser than frozendict: ImmutableMap | other merges any Mapping, whereas frozendict | other merges only a dict or frozendict and raises TypeError for other mappings that bring no | of their own. The reflected other | ImmutableMap is inherited from frozendict and is not loosened.

Examples:

>>> from xmmutablemap import ImmutableMap
>>> d = ImmutableMap(a=1, b=2)
>>> d | {"b": 3, "c": 4}
ImmutableMap({'a': 1, 'b': 3, 'c': 4})
>>> try:
...     d | ()
... except TypeError:
...     print("Cannot combine with non-mapping")
Cannot combine with non-mapping

copy() -> ImmutableMap[K, V] ¤

Return a shallow copy, which for an immutable map is itself.

frozendict.copy returns a plain frozendict for a subclass; return self instead, as the built-in does for an exact frozendict.

Examples:

>>> from xmmutablemap import ImmutableMap
>>> d = ImmutableMap(a=1, b=2)
>>> d.copy() is d
True

tree_flatten() -> tuple[tuple[V, ...], tuple[K, ...]] ¤

Flatten dict to the values (and keys), in sorted-key order.

This is used for JAX's tree flattening. Keys are sorted, as JAX does for dict and the built-in frozendict, so the leaf order matches theirs and unflattening rebuilds the map in sorted order.

Returns:

Type Description
tuple[tuple[V, ...], tuple[K, ...]]

A tuple of (values, keys). The keys are treated as auxiliary data.

Raises:

Type Description
TypeError

If the keys cannot be ordered against each other.

Examples:

>>> import jax
>>> from xmmutablemap import ImmutableMap
>>> d = ImmutableMap(a=1, b=2)
>>> d.tree_flatten()
((1, 2), ('a', 'b'))
>>> jax.tree.flatten(d)
([1, 2], PyTreeDef(CustomNode(ImmutableMap[('a', 'b')], [*, *])))

Insertion order does not matter:

>>> ImmutableMap(b=2, a=1).tree_flatten()
((1, 2), ('a', 'b'))

tree_unflatten(aux_data: tuple[K, ...], children: tuple[V, ...]) -> ImmutableMap[K, V] classmethod ¤

Unflatten into an ImmutableMap from the keys and values.

This is used for JAX's tree un-flattening.

Parameters:

Name Type Description Default
aux_data tuple[K, ...]

The keys.

required
children tuple[V, ...]

The values.

required

Examples:

>>> import jax
>>> from xmmutablemap import ImmutableMap
>>> d = ImmutableMap(a=1, b=2)
>>> children, keys = d.tree_flatten()
>>> ImmutableMap.tree_unflatten(keys, children)
ImmutableMap({'a': 1, 'b': 2})
>>> leaves, treedef = jax.tree.flatten(d)
>>> jax.tree.unflatten(treedef, leaves)
ImmutableMap({'a': 1, 'b': 2})

xmmutablemap.frozendict ¤

Bases: Mapping[K, V]

Immutable, hashable mapping.

Parameters:

Name Type Description Default
*args Mapping[K, V] | Iterable[tuple[K, V]]

At most one positional argument, as for dict.

required
**kwargs V

Key-value pairs.

required

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1, b=2)
frozendict({'a': 1, 'b': 2})
>>> frozendict()
frozendict()

__getitem__(key: K) -> V ¤

Get an item by key.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1)["a"]
1

__iter__() -> Iterator[K] ¤

Iterate over the keys, in insertion order.

Examples:

>>> from xmmutablemap import frozendict
>>> list(frozendict(a=1, b=2))
['a', 'b']

__len__() -> int ¤

Return the number of items.

Examples:

>>> from xmmutablemap import frozendict
>>> len(frozendict(a=1, b=2))
2

__contains__(key: object) -> bool ¤

Check whether a key is present.

Examples:

>>> from xmmutablemap import frozendict
>>> "a" in frozendict(a=1)
True

__reversed__() -> Iterator[K] ¤

Iterate over the keys in reverse insertion order.

Examples:

>>> from xmmutablemap import frozendict
>>> list(reversed(frozendict(a=1, b=2)))
['b', 'a']

keys() -> KeysView[K] ¤

Return a view of the keys.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1, b=2).keys()
dict_keys(['a', 'b'])

values() -> ValuesView[V] ¤

Return a view of the values.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1, b=2).values()
dict_values([1, 2])

items() -> ItemsView[K, V] ¤

Return a view of the items.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1, b=2).items()
dict_items([('a', 1), ('b', 2)])

get(key: K, /, default: V | _T | None = None) -> V | _T | None ¤

get(key: K) -> V | None
get(key: K, /, default: V | _T) -> V | _T

Get an item by key, returning default if absent.

Examples:

>>> from xmmutablemap import frozendict
>>> d = frozendict(a=1)
>>> d.get("a")
1
>>> d.get("b")
>>> d.get("b", 2)
2

copy() -> frozendict[K, V] ¤

Return a shallow copy.

As the built-in does, an exact frozendict returns itself; a subclass returns a plain frozendict.

Examples:

>>> from xmmutablemap import frozendict
>>> d = frozendict(a=1)
>>> d.copy() is d
True

__copy__() -> frozendict[K, V] ¤

Support copy.copy.

The copy module treats an exact built-in frozendict as atomic and copies a subclass through its pickle protocol. Match both.

Examples:

>>> import copy
>>> from xmmutablemap import frozendict
>>> d = frozendict(a=1)
>>> copy.copy(d) is d
True

__getnewargs__() -> tuple[dict[K, V]] ¤

Return the arguments __new__ needs to rebuild this.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1).__getnewargs__()
({'a': 1},)

__reduce_ex__(protocol: SupportsIndex) -> tuple[Any, ...] ¤

Reduce for pickling and copy, exactly as the built-in does.

The data is the __new__ argument, and only a subclass's instance __dict__ (if any) is state. Spelled out here, rather than left to object, so pickles rebuild through __new__; protocols 0 and 1, which cannot, are refused as the built-in refuses them.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1).__reduce_ex__(4)[1:]
((<class '...frozendict'>, {'a': 1}), None, None, None)

fromkeys(iterable: Iterable[K], value: Any = None) -> frozendict[K, Any] classmethod ¤

Build a frozendict with keys from iterable, all set to value.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict.fromkeys(["a", "b"], 0)
frozendict({'a': 0, 'b': 0})

__or__(other: Any) -> frozendict[Any, Any] ¤

Merge with another mapping, returning a new frozendict.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1) | {"b": 2}
frozendict({'a': 1, 'b': 2})

__ror__(other: Any) -> Any ¤

Merge into another mapping.

dict.__or__ accepts only a dict (and, on 3.15+, a frozendict). This stand-in is neither, so {...} | frozendict(...) gets NotImplemented from the left operand and lands here.

The left operand drives the merge, which reproduces the built-in's results -- including keeping the left-hand type.

As with the built-in, only a dict (or subclass) merges this way; any other Mapping gets NotImplemented, so | raises TypeError unless that mapping brings its own |.

Examples:

>>> from collections import OrderedDict
>>> from xmmutablemap import frozendict
>>> {"b": 2} | frozendict(a=1)
{'b': 2, 'a': 1}
>>> type(OrderedDict(b=2) | frozendict(a=1)).__name__
'OrderedDict'

__eq__(other: object) -> bool ¤

Compare equal to any mapping with the same items.

The built-in's C comparison returns NotImplemented for anything that is not a dict or frozendict, and leans on the other operand's reflected comparison for the rest -- which is how frozendict(a=1) == MappingProxyType({"a": 1}) comes out True. A mappingproxy knows nothing about this class, so the reflected call would not come back; handle any Mapping here directly. Non-mappings still get NotImplemented, as the built-in gives them.

Examples:

>>> from types import MappingProxyType
>>> from xmmutablemap import frozendict
>>> d = frozendict(a=1, b=2)
>>> d == {"a": 1, "b": 2} == MappingProxyType({"a": 1, "b": 2})
True
>>> d == {"a": 1}
False
>>> d.__eq__(1) is NotImplemented
True

__hash__() -> int ¤

Hash, order-independently, as the built-in does.

The value is that of the items' frozenset, which is exactly the built-in's hash.

Examples:

>>> from xmmutablemap import frozendict
>>> hash(frozendict(a=1, b=2)) == hash(frozendict(b=2, a=1))
True
>>> hash(frozendict(a=1)) == hash(frozenset({("a", 1)}))
True

__repr__() -> str ¤

Return the representation.

Examples:

>>> from xmmutablemap import frozendict
>>> frozendict(a=1, b=2)
frozendict({'a': 1, 'b': 2})
>>> frozendict()
frozendict()