Skip to content

PEP 824: None-coalescing operators - #4799

Merged
gvanrossum merged 31 commits into
python:mainfrom
cdce8p:pep824-coalescing-operators
Sep 21, 2026
Merged

gvanrossum merged 31 commits into
python:mainfrom
cdce8p:pep824-coalescing-operators

Conversation

@cdce8p

@cdce8p cdce8p commented Jan 31, 2026

Copy link
Copy Markdown
Contributor

Basic requirements (all PEP Types)

  • Read and followed PEP 1 & PEP 12
  • File created from the latest PEP template
  • PEP has next available number, & set in filename (pep-NNNN.rst), PR title (PEP 123: <Title of PEP>) and PEP header
  • Title clearly, accurately and concisely describes the content in 79 characters or less
  • Core dev/PEP editor listed as Author or Sponsor, and formally confirmed their approval
  • Author, Status (Draft), Type and Created headers filled out correctly
  • PEP-Delegate, Topic, Requires and Replaces headers completed if appropriate
  • Required sections included
    • Abstract (first section)
    • Copyright (last section; exact wording from template required)
  • Code is well-formatted (PEP 7/PEP 8) and is in code blocks, with the right lexer names if non-Python
  • PEP builds with no warnings, pre-commit checks pass and content displays as intended in the rendered HTML
  • Authors/sponsor added to .github/CODEOWNERS for the PEP

Standards Track requirements

  • PEP topic discussed in a suitable venue with general agreement that a PEP is appropriate
  • Suggested sections included (unless not applicable)
    • Motivation
    • Specification
    • Rationale
    • Backwards Compatibility
    • Security Implications
    • How to Teach This
    • Reference Implementation
    • Rejected Ideas
    • Open Issues
    • Acknowledgements
    • Footnotes
    • Change History
  • Python-Version set to valid (pre-beta) future Python version, if relevant
  • Any project stated in the PEP as supporting/endorsing/benefiting from the PEP formally confirmed such
  • Right before or after initial merging, PEP discussion thread created and linked to in Discussions-To and Post-History

📚 Documentation preview 📚: https://pep-previews--4799.org.readthedocs.build/

@cdce8p
cdce8p requested a review from a team as a code owner January 31, 2026 17:06
@cdce8p
cdce8p marked this pull request as draft January 31, 2026 17:06
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated

@nschneid nschneid left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few typos

@hugovk

hugovk commented Jan 31, 2026

Copy link
Copy Markdown
Member

@gvanrossum And please can you confirm sponsorship of this as well as #4798?

@gvanrossum

Copy link
Copy Markdown
Member

@gvanrossum And please can you confirm sponsorship of this as well as #4798?

Yes of course.

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I love that these get a serious treatment and I hope we can get the PEP to make it into 3.15. Again I have some editorial suggestions (some of which are generic and could apply to 823 as well) and some grammar nits and typos.

Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated

@Hnasar Hnasar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for writing this up in such a clear way. Exciting to see this move forward!

Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
@brianschubert brianschubert added the new-pep A new draft PEP submitted for initial review label Feb 23, 2026
@hugovk hugovk mentioned this pull request Mar 4, 2026
30 tasks
@gvanrossum

Copy link
Copy Markdown
Member

I do think that "coalescing" is a rather off-putting term, and we should come up with a better name for all proposed operations (?., ??, ??=).

Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst Outdated
@cdce8p
cdce8p requested a review from gvanrossum June 24, 2026 13:07
@gtkacz

gtkacz commented Jul 23, 2026

Copy link
Copy Markdown

Hey @cdce8p! I noticed two small things in the current PEP 824 draft that I would like to inquire about:

First, the assignment expression alternative in the "Motivation" section looks like it has its evaluation order backwards:

age = (val := user.get_age()) if val is not None else "unknown"

Because the condition of a conditional expression is evaluated first, this reads val before the assignment and raises NameError. See:

In [15]: age = (val := user.get_age()) if val is not None else "unknown"
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[15], line 1
----> 1 age = (val := user.get_age()) if val is not None else "unknown"

NameError: name 'val' is not defined

In [16]: age = val if (val := user.get_age()) is not None else "unknown"

In [17]: age
Out[17]: 20

I think the intended version is:

age = val if (val := user.get_age()) is not None else "unknown"

Second, do you think we could have the specification explicitly describe how ??= evaluates attribute and subscript targets? e.g.:

get_container()[get_key()] ??= make_default()

To me what should happen is get_container() and get_key() get evaluated exactly once, and make_default() only if the retrieved value is None. So an equivalent of this, written in current expanded code:

_container = get_container()
_key = get_key()
_current = _container[_key]

if _current is None:
    _container[_key] = make_default()

The reference implementation seems to agree with this, but I think documenting it would be useful, since the current if a is None: a = b expansion only explains simple names. It would also be worth having explicit tests for side-effectful attribute bases and subscript expressions to guarantee this behaviour

Thanks for your time and looking forward to this PEP helping my code less verbose ;)

@cdce8p

cdce8p commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for taking the time to read the draft and provide feedback @gtkacz! If you like a challenge, I've another open PR for the none-aware access operators, feel free to read #4798.

First, the assignment expression alternative in the "Motivation" section looks like it has its evaluation order backwards:
[...]

I think the intended version is:

age = val if (val := user.get_age()) is not None else "unknown"

Yes. This must have slipped through at some point.

Second, do you think we could have the specification explicitly describe how ??= evaluates attribute and subscript targets? e.g.:

get_container()[get_key()] ??= make_default()

Your intuition is correct here. Subexpressions on the left hand side are cached. This is actually similar to augmented assignments. My reference implementation for ??= reuses most of it. While reading your comment, I noticed that I myself wasn't quite sure about it. So that's certainly something which could be pointed out more explicitly in the PEP. I've added a small subsection with two more complex examples in my last commit.

@gtkacz

gtkacz commented Jul 24, 2026

Copy link
Copy Markdown

@cdce8p more than happy to help! Your other PEP 823 will also be an incredible QOL improvement, and I'd love to help with it, but I'm not sure what would you'd want me to do? I'll move the convo there ;)

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of nits, a few biggies (I don't like the "coalesce" name). Great PEP!

Comment thread .github/CODEOWNERS
Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst Outdated
cdce8p and others added 3 commits August 27, 2026 18:21
Co-authored-by: Guido van Rossum <gvanrossum@gmail.com>

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another round. While at a C++ conference I finally found the time to look at these. :-)

Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst
Comment thread peps/pep-0824.rst Outdated
Comment thread peps/pep-0824.rst
@gvanrossum
gvanrossum merged commit 96fff83 into python:main Sep 21, 2026
5 checks passed
@cdce8p
cdce8p deleted the pep824-coalescing-operators branch September 21, 2026 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-pep A new draft PEP submitted for initial review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants