diff --git a/peps/pep-0814.rst b/peps/pep-0814.rst index 36cfc0a7c85..6ca46195a05 100644 --- a/peps/pep-0814.rst +++ b/peps/pep-0814.rst @@ -6,6 +6,8 @@ Status: Draft Type: Standards Track Created: 12-Nov-2025 Python-Version: 3.15 +Post-History: `13-Nov-2025 `__ + Abstract ======== @@ -75,6 +77,15 @@ Construction - another ``frozendict``, - or an iterable of key/value tuples. +* ``frozendict(collection, **kwargs)`` combines the two previous + constructions. + +Keys must be hashable and so immutable, but values can be mutable. +Using immutable values creates a hashtable ``frozendict``. + +Creating a ``frozendict`` from a ``dict``, ``frozendict(dict)``, has a +complexity of *O*\ (*n*): items are copied (shallow copy). + The insertion order is preserved. @@ -92,8 +103,8 @@ protocol, so all expected methods of iteration are supported:: Iterating on ``frozendict``, as on ``dict``, uses the insertion order. -Hashing -------- +Hashing and Comparison +---------------------- ``frozendict`` instances can be hashable just like tuple objects:: @@ -114,6 +125,64 @@ Equality test does not depend on the items' order either. Example:: >>> a == b True +It's possible to compare ``frozendict`` to ``dict``. Example:: + + >>> frozendict(x=1, y=2) == dict(x=1, y=2) + True + + +Union operators +--------------- + +It's possible to join two ``frozendict``, or a ``frozendict`` with a +``dict``, with the merge (``|``) operator. Example:: + + >>> frozendict(x=1) | frozendict(y=1) + frozendict({'x': 1, 'y': 1}) + >>> frozendict(x=1) | dict(y=1) + frozendict({'x': 1, 'y': 1}) + +If some keys are in common, the values of the right operand are taken:: + + >>> frozendict(x=1, y=2) | frozendict(y=5) + frozendict({'x': 1, 'y': 5}) + +The update operator ``|=`` does not modify a ``frozendict`` in-place, but +creates a new ``frozendict``:: + + >>> d = frozendict(x=1) + >>> copy = d + >>> d |= frozendict(y=2) + >>> d + frozendict({'x': 1, 'y': 2}) + >>> copy # left unchanged + frozendict({'x': 1}) + +See also :pep:`584` "Add Union Operators To dict". + + +Copy +---- + +``frozencopy.copy()`` returns a shallow copy. In CPython, it simply +returns the same ``frozendict`` (new reference). + +Use ``copy.deepcopy()`` to get a deep copy. + +Example:: + + >>> import copy + >>> d = frozendict(mutable=[]) + >>> shallow_copy = d.copy() + >>> deep_copy = copy.deepcopy(d) + >>> d['mutable'].append('modified') + >>> d + frozendict({'mutable': ['modified']}) + >>> shallow_copy # modified! + frozendict({'mutable': ['modified']}) + >>> deep_copy # unchanged + frozendict({'mutable': []}) + Typing ------ @@ -138,10 +207,12 @@ C API Add the following APIs: -* ``PyFrozenDict_Type`` -* ``PyFrozenDict_New(collection)`` function +* ``PyAnyDict_Check(op)`` macro +* ``PyAnyDict_CheckExact(op)`` macro * ``PyFrozenDict_Check()`` macro * ``PyFrozenDict_CheckExact()`` macro +* ``PyFrozenDict_New(collection)`` function +* ``PyFrozenDict_Type`` Even if ``frozendict`` is not a ``dict`` subclass, it can be used with ``PyDict_GetItemRef()`` and similar "PyDict_Get" functions. @@ -269,12 +340,10 @@ Relationship to PEP 603 frozenmap * ``excluding(key)`` * ``union(mapping=None, **kw)`` -========== ============== ============== -Complexity ``frozenmap`` ``frozendict`` -========== ============== ============== -Lookup *O*\ (log *n*) *O*\ (1) -Copy *O*\ (1) *O*\ (*n*) -========== ============== ============== + These methods to mutate a ``frozenmap`` have a complexity of *O*\ (1). + +* A mapping lookup (``mapping[key]``) has a complexity of *O*\ (log *n*) + with ``frozenmap`` and a complexity of *O*\ (1) with ``frozendict``. Reference Implementation