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 |
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 |
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()