diff --git a/peps/pep-0824.rst b/peps/pep-0824.rst index d0943b0bf61..00476d24033 100644 --- a/peps/pep-0824.rst +++ b/peps/pep-0824.rst @@ -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 ---------------------------- @@ -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 =========