# PEP 824: None-coalescing operators

**URL:** <https://discuss.python.org/t/pep-824-none-coalescing-operators/109161>\
**Category:** PEPs\
**Created:** [September 21, 2026, 10:33pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161 "2026-09-21T22:33:06Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![cdce8p](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cdce8p/32/3575_2.png) [@cdce8p](https://discuss.python.org/u/cdce8p)\
**Post date:** [September 21, 2026, 10:33pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/1 "2026-09-21T22:33:06Z")

</div>

Building on the ideas from [PEP 505](https://peps.python.org/pep-0505/) and after many discussions over the years, I’m happy to present **`PEP 824: None-coalescing operators`**. Please be sure to also check out the discussion for the companion [PEP 823](https://discuss.python.org/t/pep-823-none-aware-access-operators/109159).

## Abstract

This PEP proposes adding two new operators.

- The “`None`-coalescing” operator `??`
- The “`None`-coalescing assignment” operator `??=`

The general idea is to provide a conditional operator, similar to `or`, which instead of truthiness, checks for `None` values.

The “`None`-coalescing” operator evaluates the left-hand side, checks whether it is `not None`, and if not, returns the result. If the value is `None`, the right-hand side is evaluated and returned.

The “`None`-coalescing assignment” operator will only assign the right-hand side to the left-hand side if the left-hand side evaluates to `None`.

They are roughly equivalent to:

```python
# a ?? b
_t if ((_t := a) is not None) else b

# a ??= b
if a is None:
    a = b

```

–  
An interactive demo is available here: [https://pep823-and-pep824-demo.pages.dev/](https://pep823-and-pep824-demo.pages.dev/)

> **[PEP 824 – None-coalescing operators | peps.python.org](https://peps.python.org/pep-0824/)**
>
> This PEP proposes adding two new operators.

---

<div class="post-metadata">

**Author:** ![AlSweigart](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/alsweigart/32/12237_2.png) [@AlSweigart](https://discuss.python.org/u/AlSweigart)\
**Post date:** [September 22, 2026, 2:48am UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/2 "2026-09-22T02:48:38Z")

</div>

Just to clarify, the splitting of PEP 505 into these two PEPs is so that they can be considered independently? As in, we could accept one but not the other?

---

<div class="post-metadata">

**Author:** ![weixlu](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/weixlu/32/34086_2.png) [@weixlu](https://discuss.python.org/u/weixlu)\
**Post date:** [September 22, 2026, 7:45am UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/3 "2026-09-22T07:45:59Z")

</div>

I think using `??=` is a good idea. When I write code, I don’t use conditional expressions very often, for the reasons the PEP describes. In the code I work on, the difference between `age = user.age ?? "unknown"` and `age = user.age or "unknown"` feels small, since `0` is usually not a value I need to keep. That’s only my own experience, though. Using `??` does make the check more precise, because it filters out only `None`.

---

<div class="post-metadata">

**Author:** ![cdce8p](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cdce8p/32/3575_2.png) [@cdce8p](https://discuss.python.org/u/cdce8p)\
**Post date:** [September 22, 2026, 9:37am UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/4 "2026-09-22T09:37:26Z")

</div>

> [@AlSweigart](#):
>
> Just to clarify, the splitting of PEP 505 into these two PEPs is so that they can be considered independently? As in, we could accept one but not the other?

Correct. While they do share a theme and complement each other, it would be possible to only accept either one of the two.

---

<div class="post-metadata">

**Author:** ![mikeshardmind](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/mikeshardmind/32/14381_2.png) [@mikeshardmind](https://discuss.python.org/u/mikeshardmind)\
**Post date:** [September 22, 2026, 10:13am UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/5 "2026-09-22T10:13:36Z")

</div>

Of the pair of proposals, I’m more enthusiastically positive about this one. I’m glad to see the intentional limiting of both to handling exactly `None`.

Changing the existing None checks I have where 824 could be used is not something that would push me to upgrade minimum python versions any faster, but it is a real improvement and may help prevent people from using `or` when there is a potential falsey value they had not considered.

---

<div class="post-metadata">

**Author:** ![effigies](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/effigies/32/35835_2.png) [@effigies](https://discuss.python.org/u/effigies)\
**Post date:** [September 22, 2026, 12:16pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/6 "2026-09-22T12:16:32Z")

</div>

I would be very glad to see this accepted, and I am also glad to see it limited to exactly `None`. Extending to sentinels or other objects would replicate the pitfalls of ` __bool__ `.

Just a note on the precedence:

> ```python
> # x or y ?? 2
> (x or y) ?? 2
> 
> # "Hello" if x ?? True else 0
> "Hello" if (x ?? True) else 0
> 
> ```

and

> Furthermore, setting the precedence between `or` and conditional expressions matches other languages which have implemented the operator, like JS [[8]](https://peps.python.org/pep-0824/#js-precedence) and C# [[10]](https://peps.python.org/pep-0824/#csharp-precedence).

This is correct, but the JS and C# examples are interesting in that `x || y ?? 2` is a type error in C# and a syntax error in JS. It may be worth exploring whether other languages permit intermixing with boolean operators, or if Python would be unique in this respect.

That said, I find the JS behavior surprising and annoying, so agree with the current design that parentheses should remain optional when precedence matches intent.

---

<div class="post-metadata">

**Author:** ![tusharc](https://avatars.discourse-cdn.com/v4/letter/t/bbe5ce/32.png) [@tusharc](https://discuss.python.org/u/tusharc)\
**Post date:** [September 22, 2026, 12:59pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/7 "2026-09-22T12:59:28Z")

</div>

Thank you for putting this PEP together. I support this. I think PEP 824 is clearer than earlier versions like PEP 505. I think splitting this + PEP 823 was a good idea. Like others in this thread, I appreciate the intentional decision to only handle `None` and not anything false-y.

I think that, in practice, I would have more of a use for [PEP 823: None-aware access operators](https://discuss.python.org/t/pep-823-none-aware-access-operators/109159) ; but both PEPs describe features I miss every time I switch over from TypeScript.

---

<div class="post-metadata">

**Author:** ![Boss\_1s](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/boss_1s/32/37501_2.png) [@Boss\_1s](https://discuss.python.org/u/Boss_1s)\
**Post date:** [September 22, 2026, 2:17pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/8 "2026-09-22T14:17:40Z")

</div>

What if both `Coalesce` operators had their own dunder methods to change the check/assignment for `None` to something else like a custom `Sentinel` object? Would that be redundant or overly confusing?

Something like:

```python
class Foo:
    MISSING = sentinel("MISSING")

    def __init__ (self, bar=MISSING) -> None:
        self.bar = bar

    def __cgetattribute__ (self, name, fallback): # ??
        # None-coalescing becomes MISSING-coalescing
        return fallback ?? self.name

    def __csetattr__ (self, name, value): # ??=
        # None-coalescing assignment becomes MISSING-coalescing assignment
        if self. __cgetattribute__ (self, name) is MISSING:
            super(). __setattr__ (name, value)

obj = Foo()

obj.bar ?? "unknown" # Returns "unknown"

obj.bar ??= "bax" # obj.bar is now "bax"
obj.bar ??= "baq" # obj.bar is still "bax"

obj.bar ?? "unknown" # Returns "bax"
        

```

(This example can be improved on)

---

<div class="post-metadata">

**Author:** ![a-reich](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/a-reich/32/5885_2.png) [@a-reich](https://discuss.python.org/u/a-reich)\
**Post date:** [September 22, 2026, 2:57pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/9 "2026-09-22T14:57:14Z")

</div>

I’m +1 or maybe +0.5 on this (PEP 823 would make a bit more of a difference for me), as a nice pragmatic convenience. I think it makes sense to keep the scope narrow and behavior simple by targeting only None.

My only question is… how did you decide on this color for the bikeshed? 😅 When defining new syntax fore a feature there are always lots of possibilities for how to “spell” it, especially when introducing the new ? symbol. Is the rationale basically that other languages use these two spellings for the same concepts?

---

<div class="post-metadata">

**Author:** ![Monarch](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/monarch/32/18530_2.png) [@Monarch](https://discuss.python.org/u/Monarch)\
**Post date:** [September 22, 2026, 6:48pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/10 "2026-09-22T18:48:38Z")

</div>

Massive +1. I’ve written libraries for dealing with APIs with hundreds of nested fields, most of them optional, and I’ve spent a lot of time making sure the user only has to deal with typed objects that are nice to work with in Python. That includes not making them deal with optionals or missing data unless absolutely necessary. These (PEP 823 & PEP 824) operators would make my libraries’ code much nicer by eliminating a ridiculous amount of repetitive `None` checks.

---

<div class="post-metadata">

**Author:** ![cdce8p](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cdce8p/32/3575_2.png) [@cdce8p](https://discuss.python.org/u/cdce8p)\
**Post date:** [September 23, 2026, 2:00pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/11 "2026-09-23T14:00:17Z")

</div>

> [@a-reich](#):
>
> My only question is… how did you decide on this color for the bikeshed? 😅 When defining new syntax fore a feature there are always lots of possibilities for how to “spell” it, especially when introducing the new ? symbol. Is the rationale basically that other languages use these two spellings for the same concepts?

The question how to read the expression out loud was brought up during review. These are just some suggestions we did come up with. If there are other better options, I’m happy to include them. Just keep in mind that these are only suggestions. If the PEP is accepted, I’d think some option might emerge organically anyway which can but doesn’t need to be the suggested one in the PEP.

The section from the PEP: [Reading expressions out loud](https://peps.python.org/pep-0824/#reading-expressions-out-loud)

---

<div class="post-metadata">

**Author:** ![CarrotManMatt](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/carrotmanmatt/32/29860_2.png) [@CarrotManMatt](https://discuss.python.org/u/CarrotManMatt)\
**Post date:** [September 23, 2026, 2:37pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/12 "2026-09-23T14:37:17Z")

</div>

Was @a-reich referring to the way to “say” the construct or the actual python syntax?

---

<div class="post-metadata">

**Author:** ![a-reich](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/a-reich/32/5885_2.png) [@a-reich](https://discuss.python.org/u/a-reich)\
**Post date:** [September 23, 2026, 2:44pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/13 "2026-09-23T14:44:09Z")

</div>

Sorry, I was referring to the actual syntax. i.e. how come `a ?? b` and not say `a ? b`, `a ?| b`, `a coalesce b`, or some other character combination. I didn’t spot anywhere in the PEP explicitly stating this other than the rejected idea about a keyword.

---

<div class="post-metadata">

**Author:** ![cdce8p](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cdce8p/32/3575_2.png) [@cdce8p](https://discuss.python.org/u/cdce8p)\
**Post date:** [September 23, 2026, 4:54pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/14 "2026-09-23T16:54:14Z")

</div>

My bad. Almost all languages with coalescing operators use `??` and `??=`. AFAIR all prior discussions, including PEP 505, used them as well.

Why `??` and not a single `?`: The `None`-coalescing operator is a conditional operator. As such it’s more closely related to `and` / `or` than binary operators `+`, `-`, `&`, `|`, … Looking at other languages again, `and` is often spelled as `&&`, `or` as `||`. Both use two chars to differentiate them from their binary counterparts.

---

<div class="post-metadata">

**Author:** ![mcgfeller](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/mcgfeller/32/10724_2.png) [@mcgfeller](https://discuss.python.org/u/mcgfeller)\
**Post date:** [September 27, 2026, 12:25pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/15 "2026-09-27T12:25:44Z")

</div>

+1. Occurs over and over in my code.

---

<div class="post-metadata">

**Author:** ![svioletg](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/svioletg/32/37602_2.png) [@svioletg](https://discuss.python.org/u/svioletg)\
**Post date:** [September 27, 2026, 8:32pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/16 "2026-09-27T20:32:13Z")

</div>

+1 from me, I was very excited to see this idea get revitalized as a new PEP.

@a-reich While I usually like that Python generally prefers keywords over symbols (like `and`/`or`), I think in this case `coalesce` doesn’t provide much benefit mainly because anyone learning Python and unfamiliar with the concept might not immediately grasp what coalesce is supposed to mean in this context, and although the “formal” name for the operation is nullish-coalescing, I would assume most would read `a ?? b` aloud not as “a coalesce b” but “a if not null, else b”, which is basically already what we have now in the form of `a if a is not None else b`, so an already-established symbol I think makes more sense as the choice for that shortcut.

---

<div class="post-metadata">

**Author:** ![hlovatt](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hlovatt/32/36838_2.png) [@hlovatt](https://discuss.python.org/u/hlovatt)\
**Post date:** [September 28, 2026, 2:09am UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/17 "2026-09-28T02:09:16Z")

</div>

Really dislike the `??` notation. Not Python like at all! How about `a ifnone b`? Don’t bother with `??=` at all, too niche.

---

<div class="post-metadata">

**Author:** ![barry](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/barry/32/42_2.png) [@barry](https://discuss.python.org/u/barry)\
**Post date:** [September 28, 2026, 6:04pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/18 "2026-09-28T18:04:33Z")

</div>

I once suggested `otherwise` but PEP 824 [explicitly rejects this](https://peps.python.org/pep-0824/#add-new-soft-keyword)\[1\].

* * *

1. and other soft keywords

---

<div class="post-metadata">

**Author:** ![monk-time](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/monk-time/32/516_2.png) [@monk-time](https://discuss.python.org/u/monk-time)\
**Post date:** [September 28, 2026, 6:38pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/19 "2026-09-28T18:38:32Z")

</div>

People suggesting other syntax options should also explain why this feature should use _anything else_ but the notation that is already widely used in a dozen of other major languages. The value of reusing an existing convention is high, and the cost of breaking that expectation for newcomers who are already familiar with the convention is also high and should be justified.

This is not some experimental feature that is breaking a new ground in programming and therefore needing a brainstorm over syntax.

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [September 28, 2026, 7:30pm UTC](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161/20 "2026-09-28T19:30:41Z")

</div>

The `??` syntax has a very natural pairing with `?.`, and since they are two parts of what should usually be the same expression, it makes sense for both to have some level of consistency.\[1\]

By “natural pairing” I mean that `a?.b ?? c` should be a typical usage, where `None` is only really a special intermediate value and not an intentional result. Translated into current code, this would be `a.b if a is not None and a.b is not None else c`\[2\]. Both expressions are pretty good in this respect - the former uses punctuation operators and the latter using textual operators, and the precedence works as each naturally reads.\[3\]

* * *

1. It’s irrelevant since I’ve withdrawn my own efforts on this, but I wouldn’t have split the PEP up into two. The value of `??` is strongest when `?.` exists, and with either half of the syntax missing, the value quickly becomes zero or negative. 

2. Without the repeated evaluations, of course. 

3. Though, of course, I don’t prefer either syntax over a traversal helper function or a data model that simply doesn’t allow `None`s to reach my business logic.

[Next page](https://discuss.python.org/t/pep-824-none-coalescing-operators/109161.md?page=2)
