Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 92 additions & 14 deletions peps/pep-0824.rst
Original file line number Diff line number Diff line change
Expand Up @@ -307,20 +307,92 @@ There are no new security implications from this proposal.
How to Teach This
=================

In a practical sense it might be helpful to think of the "``None``-coalescing"
operator ``??`` as a special case for the conditional ``or``
operator, with the caveat that ``??`` checks for ``is not None`` instead
of truthiness. As such it makes sense to include ``??`` when teaching
the other conditional operators ``and`` and ``or``.

The "``None``-coalescing assignment" operator ``??=`` can be best
thought of as a conditional assignment operator. As it is closely
related to ``??``, explaining these together would make sense.
Though it looks related to binary assignment operators like ``+=``
as well, it is worth pointing out the distinction between these.
Since ``??=`` is a **conditional** assignment operator, the right-hand
side will be skipped entirely in some case, while ``+=`` always
evaluates both sides.
Prerequisites
-------------

Students should already know how the short-circuit operators ``and`` and
``or`` work, and what counts as truthy and falsy values.

Basics
------

The ``??`` operator is a short-circuit operator like ``and`` and ``or``
that only checks whether its left argument is ``None``. The others check
for truthiness or falsiness, and treat values like ``0``, ``""`` and ``[]``
as falsy.

``a ?? b`` is equivalent to ``a if a is not None else b``, except that
``a`` is only evaluated once. Similarly, ``a or b`` is equivalent to
``a if a else b``, with ``a`` evaluated only once.

For example, ``d.get(key) ?? make_default()`` calls ``make_default()``
only when the key is missing or its value is ``None``. By contrast,
``d.get(key, make_default())`` always evaluates ``make_default()``, and
still returns ``None`` when the key is present with a ``None`` value.

The ``??=`` operator is the conditional assignment operator derived from
``??``. ``a ??= b`` has the same effect as ``a = a ?? b``, except that
there is no assignment when ``a`` is not ``None``. Like augmented
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``.

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 ``or``, ``??`` is associative: ``(a ?? b) ?? c`` has the same
meaning as ``a ?? (b ?? c)``.

Operator precedence
-------------------

The ``??`` operator has a lower precedence than ``or`` and ``and``.
Thus, ``a or b ?? c`` means ``(a or b) ?? c``, and ``a ?? b and c``
means ``a ?? (b and c)``. To get the opposite grouping, use
``a or (b ?? c)`` or ``(a ?? b) and c``.

This precedence is a convention. For clarity, we recommend always adding
parentheses when mixing ``??`` with ``and`` or ``or``.

When to use
-----------

This is useful when you find yourself writing expressions like
``a if a is not None else b`` a lot. It can also replace
``a if a else b`` and ``a or b`` when a ``None`` check is intended:
use ``a ?? b`` for either.

The ``??=`` operator is handy for providing defaults for arguments.
For example:

.. code-block:: python
def add_default_user(users: list[User] | None = None) -> list[User]:
if users is None:
users = []
users.append(create_default_user())
return users
This can be compacted to:

.. code-block:: py824
def add_default_user(users: list[User] | None = None) -> list[User]:
users ??= []
users.append(create_default_user())
return users
When not to use
---------------

Do not use these operators when you also want to check for other falsy
values. For example, ``name ?? "unknown"`` preserves an empty string,
whereas ``name or "unknown"`` replaces ``""`` with ``"unknown"``.

Reading expressions out loud
----------------------------
Expand Down Expand Up @@ -612,6 +684,12 @@ Footnotes
(https://perldoc.perl.org/perlop#Assignment-Operators)
Change History
==============

* 20-Oct-2026: Turned `How to Teach This`_ into a mini-tutorial.


Copyright
=========

Expand Down
Loading