From 05221f201802f9e8c5228a4a559d6db670caa6f2 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 31 Oct 2026 19:35:24 +0100 Subject: [PATCH] PEP 824: Updates --- peps/pep-0824.rst | 75 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/peps/pep-0824.rst b/peps/pep-0824.rst index 00476d24033..549ba3fb393 100644 --- a/peps/pep-0824.rst +++ b/peps/pep-0824.rst @@ -180,21 +180,36 @@ If the value is ``not None``, the cached result is returned. If it is # a ?? b _t if ((_t := a) is not None) else b +.. _`spec-chaining`: + +Chaining +******** + +An expression like ``a ?? b ?? c ?? d`` evaluates its subexpressions +(``a``, ``b``, etc.) from left to right until it finds a value that is +not ``None`` or reaches the end. If all values are ``None``, the result +is ``None``. + +Like ``and`` and ``or``, ``??`` is **associative**: ``(a ?? b) ?? c`` +has the same meaning as ``a ?? (b ?? c)``. + Precedence ********** The precedence of ``??`` will be lower than ``or`` but higher than conditional expressions. Parentheses can be added as necessary to -modify the precedence of individual expressions. A few examples of -how implicit parentheses would be placed: +modify the precedence of individual expressions. Setting the precedence +like this means ``or`` can easily be replaced with ``??`` where +appropriate without any surprises. A few examples of how implicit +parentheses would be placed: .. code-block:: py824 # x or y ?? 2 (x or y) ?? 2 - # "Hello" if x ?? True else 0 - "Hello" if (x ?? True) else 0 + # a ?? b if c else d + (a ?? b) if c else d AST changes *********** @@ -242,6 +257,9 @@ and assignment of the right-hand side are skipped. if a is None: a = b +This has the same effect as ``a = a ?? b``, except that there is no +assignment when ``a`` is not ``None``. + Subexpression caching ********************* @@ -337,6 +355,8 @@ assignment, it evaluates the target only once. For example, in ``a[index()] ??= b``, ``index()`` is called only once. The right-hand side is evaluated only when the target's value is ``None``. +.. _`how-to-chaining`: + Chaining -------- @@ -345,8 +365,8 @@ An expression like ``a ?? b ?? c ?? d`` evaluates its subexpressions not ``None`` or reaches the end. If all values are ``None``, the result is ``None``. -Like ``or``, ``??`` is associative: ``(a ?? b) ?? c`` has the same -meaning as ``a ?? (b ?? c)``. +Like ``and`` and ``or``, ``??`` is **associative**: ``(a ?? b) ?? c`` +has the same meaning as ``a ?? (b ?? c)``. Operator precedence ------------------- @@ -446,7 +466,7 @@ Deferred Ideas operators ``?.`` and ``?[ ]``. As the "``None``-coalescing" operators have their own use cases, the "``None``-aware access" operators were moved into a separate document, see :pep:`823`. Both proposals can be -adopted independently of each other. +adopted independently of each other, though they do work well together. Other conditional assignment operators -------------------------------------- @@ -458,6 +478,23 @@ conditional assignment operators ``&&=`` and ``||=`` in other programming languages such as ECMAScript (a.k.a. JavaScript) [#js_and_assign]_ [#js_or_assign]_, Ruby [#ruby]_ and Perl [#perl]_. +Add ``operator.coalesce`` +------------------------- + +It was suggested to add a new ``coalesce`` function to the ``operator`` +module. This was deferred since the other boolean operators ``and`` and +``or`` do not have a corresponding function either yet. +:py:func:`operator.and_` and :py:func:`operator.or_` exist but those +map to the binary operations ``&`` and ``|``. + +Add a combined ``??:=`` operator +-------------------------------- + +Another idea was to add an operator which combines ``??=`` and ``:=`` +into one: ``??:=``. It could be used like an assignment expression but +would only assign values if the target is ``None``. This is outside the +scope of this PEP. + Rejected Ideas ============== @@ -539,6 +576,18 @@ This was rejected since other operators with multiple steps, for example issue, existing synchronization primitives like locks should be used instead. +Add protocol to customize coalesce behavior +------------------------------------------- + +It was discussed to make the coalesce behavior customizable via a +protocol. + +One of the advantages of ``??`` is that it is limited to only ``None``. +This avoids the ambiguity that would come with using ``or`` where it is +not always immediately obvious if a value will be truthy, especially +considering that objects can define a custom :py:meth:`object.__bool__` +method. + Common objections ================= @@ -619,8 +668,8 @@ Use custom sentinels instead of ``None`` ---------------------------------------- In Python 3.15, :pep:`661` added the option to define custom sentinels -using ``sentinel(...)``. This addressed an issue in cases where ``None`` -itself is a valid value and thus could not be used as sentinel. +using :py:class:`sentinel`. This addressed an issue in cases where +``None`` itself is a valid value and thus could not be used as sentinel. In general though, ``None`` will still be preferred if a sentinel is needed, simply because it already exists for that exact purpose and @@ -687,6 +736,14 @@ Footnotes Change History ============== +* 31-Oct-2026: + + - Added section on `Chaining `_ to the specification. + - Added `Add operator.coalesce`_ and `Add a combined ??:= operator`_ + as deferred ideas. + - Added `Add protocol to customize coalesce behavior`_ as rejected + idea. + * 20-Oct-2026: Turned `How to Teach This`_ into a mini-tutorial.