# Is the walrus Operator antipattern?

**URL:** <https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906>\
**Category:** Python Help\
**Created:** [April 11, 2025, 1:59am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906 "2025-04-11T01:59:38Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Pynerds](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pynerds/32/27180_2.png) [@Pynerds](https://discuss.python.org/u/Pynerds)\
**Post date:** [April 11, 2025, 1:59am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/1 "2025-04-11T01:59:39Z")

</div>

I recently discovered the _walrus operator_ (`:=`) and have mixed feelings about it.  
It feels like an odd exception to Python’s usual emphasis on readability.

**What puzzled me:**

- Python famously rejects `++`/`--` operators for being “unpythonic,” yet `:=` exists.
- Most cases I’ve seen (e.g., `while (line := file.readline())`) could just use multiple lines.

**Am I missing something?**

- Are there _legitimate_ cases where `:=` is the cleanest solution?
- Or is it a niche feature that encourages bad habits?

_(Source: [Walrus Operator](https://www.pynerds.com/walrus-operator-in-python/))_

---

<div class="post-metadata">

**Author:** ![MegaIng](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/megaing/32/16162_2.png) [@MegaIng](https://discuss.python.org/u/MegaIng)\
**Post date:** [April 11, 2025, 2:08am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/2 "2025-04-11T02:08:52Z")

</div>

> [@Pynerds](#):
>
> Most cases I’ve seen (e.g., `while (line := file.readline())`) could just use multiple lines.

Please try to turn this exact example into multiple lines without repeating `file.readline()`. Yes, it’s possible, but it doesn’t read as well.

Any kind of syntax sugar can be dismissed as “just use more lines instead”, but that is missing the point.

You can search back on the mailing lists from around the time this operator was added. You will find dozens of people making the exact same arguments you are making and many people making counter arguments.

---

<div class="post-metadata">

**Author:** ![MRAB](https://avatars.discourse-cdn.com/v4/letter/m/e9c0ed/32.png) [@MRAB](https://discuss.python.org/u/MRAB)\
**Post date:** [April 11, 2025, 2:19am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/3 "2025-04-11T02:19:37Z")

</div>

It’s convenient when using the `re` module:

```python
if m := re.match(first_pattern, text):
    ...
elif m := re.match(second_pattern, text):
    ...
else:
    ...

```

That’s nicer than:

```python
m = re.match(first_pattern, text)
if m:
    ...
else:
    m = re.match(second_pattern, text)
    if m:
        ...
    else:
        ...

```

---

<div class="post-metadata">

**Author:** ![tim.one](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tim.one/32/282_2.png) [@tim.one](https://discuss.python.org/u/tim.one)\
**Post date:** [April 11, 2025, 6:30am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/4 "2025-04-11T06:30:14Z")

</div>

.

> [@Pynerds](#):
>
> I recently discovered the _walrus operator_ (`:=`) and have mixed feelings about it.  
> It feels like an odd exception to Python’s usual emphasis on readability.

Or it isn’t 😉. Seriously, in **some** contexts it’s more readable. @MegaIng and @MRAB gave examples. Like:

```python
while buf := some_binary_file.read(BUFSIZE):
    # deal with `buf`

```

they’re of the very simple form `while result := function()`. There’s really no gain in clarity (the contrary) by splitting that across multiple lines and typing `buf` out an additional time.

So stick to that. At the time (about 5 years ago), Guido (the language’s designer) and I were the strongest advocates for adding the walrus, and repeatedly stressed that it was intended to be used only when it _actually increased_ clarity. I went through many thousands of lines of code “by eyeball” at the time, and only found a few dozen cases where it would be a clear improvement. But they were indeed clear (if small) improvements.

So it’s not often! If, e.g., you need to wrap an assignment expression in parentheses, you’re probably pushing the intent.

It’s intended to be a simple feature for use in simple contexts. That’s why, e.g., the binding target is restricted to be a simple identifier (no, e.g. , subscripted or attribute targets, or magical unpacking of an iterable result into multiple targets). An assignment _statement_ can be far more complex than an assignment expression.

Python could certainly have lived without it. But in the relatively few cases where it’s “just right”, it’s _very_ “Pythonic” to my (& Guido’s) eyes: efficiently and clearly communicating _intent_ with a minimum of syntactic noise and/or repetition.

Of course people will, at times, use it in unintended ways. There’s nothing to stop them from, e.g., using 117 blanks per indentation level either - Python never aimed to make it impossible to write ugly code;

---

<div class="post-metadata">

**Author:** ![rsdenijs](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rsdenijs/32/21739_2.png) [@rsdenijs](https://discuss.python.org/u/rsdenijs)\
**Post date:** [April 11, 2025, 7:58am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/5 "2025-04-11T07:58:44Z")

</div>

I like to use it sometimes when building data structures with reusable elements

`{'thing': thing:=do_something(), 'other_thing': OtherThing(thing=thing)}`

Shoot me.

---

<div class="post-metadata">

**Author:** ![hprodh](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hprodh/32/22529_2.png) [@hprodh](https://discuss.python.org/u/hprodh)\
**Post date:** [April 11, 2025, 9:13am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/6 "2025-04-11T09:13:29Z")

</div>

I use it mainly in the preprocessing steps of my functions.  
Before the walrus, I was struggling to choose among many possible ways doing that kind of preprocessing :

```python
def process_mix(data0, data1):
    assert data0.parameter == data1.parameter # safety check
    parameter = data0.parameter # parameter extraction
    ...

```

Now there is an all-at once way

```python
def process_mix(data0, data1):
    assert (parameter := data0.parameter) == data1.parameter
    ...

```

Just a detail, though.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [April 11, 2025, 9:46am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/7 "2025-04-11T09:46:48Z")

</div>

> [@hprodh](#):
>
> Now there is an all-at once way
> 
> ```python
> def process_mix(data0, data1):
> assert (parameter := data0.parameter) == data1.parameter
> ...
> 
> ```
> 
> Just a detail, though.

Don’t do this. Assertions should NEVER have functionality other than the actual assertion.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [April 11, 2025, 9:48am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/8 "2025-04-11T09:48:01Z")

</div>

> [@Rosuav](#):
>
> Don’t do this. Assertions should NEVER have functionality other than the actual assertion.

Though - on second thoughts, it’s not the walrus that’s the problem here, it’s the assertion. This should most likely be a simple if/raise, not an assert.

---

<div class="post-metadata">

**Author:** ![oscarbenjamin](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/oscarbenjamin/32/1209_2.png) [@oscarbenjamin](https://discuss.python.org/u/oscarbenjamin)\
**Post date:** [April 11, 2025, 9:55am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/9 "2025-04-11T09:55:12Z")

</div>

> [@Pynerds](#):
>
> Most cases I’ve seen (e.g., `while (line := file.readline())`) could just use multiple lines.

This is a poor choice of example because the alternative without the Walrus operator in this case is awkward and also `for line in file` is better anyway.

Maybe your experience of the Walrus operator is somewhat like mine in that it appeared and then I saw other people using it enthusiastically but usually in situations where it isn’t needed. In a quick review of one codebase (`git grep -C3 :=`) I find that about 50% of the time when the Walrus operator is used it could just be an assignment on the line above e.g.:

```python
if x := func():
    do_thing(x)

```

I don’t mind it if the name being assigned to appears right after `if` but I also see more complex examples where the assignment can be anywhere:

```python
if func(a, b, x := g()):
   do_thing(x)

```

There are some `while` loops but the situations where the alternative without the Walrus would be awkward are almost all `if/elif` cases like @MRAB’s example:

```python
if one_thing():
    #
elif x := func():
    do_thing(x)
elif ...

```

---

<div class="post-metadata">

**Author:** ![hprodh](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hprodh/32/22529_2.png) [@hprodh](https://discuss.python.org/u/hprodh)\
**Post date:** [April 11, 2025, 10:17am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/10 "2025-04-11T10:17:49Z")

</div>

> [@Rosuav](#):
>
> This should most likely be a simple if/raise, not an assert.

I know, but these are meant to avoid silent bugs due to inconsistently formatted data in personal codes. It is not meant for production and I use it when I don’t want to spend time and lines on exception handling.

---

<div class="post-metadata">

**Author:** ![bwoodsend](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/bwoodsend/32/4027_2.png) [@bwoodsend](https://discuss.python.org/u/bwoodsend)\
**Post date:** [April 11, 2025, 10:28am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/11 "2025-04-11T10:28:24Z")

</div>

> [@hprodh](#):
>
> Now there is an all-at once way
> 
> ```python
> def process_mix(data0, data1):
> assert (parameter := data0.parameter) == data1.parameter
> ...
> 
> ```

You do realise that entire line will be skipped if someone runs with `python -O`?

---

<div class="post-metadata">

**Author:** ![chepner](https://avatars.discourse-cdn.com/v4/letter/c/22d042/32.png) [@chepner](https://discuss.python.org/u/chepner)\
**Post date:** [April 11, 2025, 11:26am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/12 "2025-04-11T11:26:17Z")

</div>

I’m not faulting you if you haven’t done so yet, but you should read the PEP which introduced the idea, because it goes into great detail discussing the use cases for which such an operator was desired.

> **[PEP 572 – Assignment Expressions | peps.python.org](https://peps.python.org/pep-0572/)**
>
> This is a proposal for creating a way to assign to variables within an expression using the notation NAME := expr.

I will note that things like `++` are often used to modify an index during iteration, and Python already has better abstractions for iteration that don’t involve explicit indexing.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [April 11, 2025, 12:32pm UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/13 "2025-04-11T12:32:26Z")

</div>

> [@hprodh](#):
>
> I know, but these are meant to avoid silent bugs due to inconsistently formatted data in personal codes. It is not meant for production and I use it when I don’t want to spend time and lines on exception handling.

Using assert in this way is a bad habit that should be avoided all the time. Just because you happen to not be using `-O` right now doesn’t mean that it’s safe to abuse assertions in this way; you never know what you’ll do in the future, and the assert will cause yourself unnecessary pain.

---

<div class="post-metadata">

**Author:** ![hprodh](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hprodh/32/22529_2.png) [@hprodh](https://discuss.python.org/u/hprodh)\
**Post date:** [April 26, 2025, 12:47pm UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/14 "2025-04-26T12:47:01Z")

</div>

Well, that’s right…  
What I haven’t said is that I use these assertions within functions taking numerous numpy arrays with numerous dimensions, I basically use the assertions to check whether the dimension sizes are verifying some patterns.  
While a first run of the script runs, the generated dimensions are checked so the -O run will just be right. Therefore using assertions here feels ok to me.

Using walrus operator in assertions must be done only if the assigned values (the dimension sizes in my cases) are only used within other assertions.

I did not want to do an OT on here, assertions are not the subject.

---

<div class="post-metadata">

**Author:** ![hprodh](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hprodh/32/22529_2.png) [@hprodh](https://discuss.python.org/u/hprodh)\
**Post date:** [April 26, 2025, 12:53pm UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/15 "2025-04-26T12:53:08Z")

</div>

I read PEP572 and something did catch my attention :

```python
lambda line: (m := re.match(pattern, line)) and m.group(1) # Valid

```

By carefully engineering the usage of walrus operators and `and` operators, one can then generate multistep (equivalent of multiline but one-lined) lambda functions. I think it opens ways to have heavy-lifting lambda functions that were not possible before. (Not sure about the use cases but probably in-topic here)

---

<div class="post-metadata">

**Author:** ![CAM-Gerlach](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cam-gerlach/32/3688_2.png) [@CAM-Gerlach](https://discuss.python.org/u/CAM-Gerlach)\
**Post date:** [April 27, 2025, 10:58am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/16 "2025-04-27T10:58:55Z")

</div>

I’d normally agree with you that `assert` abuse should be avoided, but if as the user asserts (pun intended) this is merely a safety check that is not required in production and can be skipped for performance reasons, then the “before the walrus” example is at least arguably a legitimate use of assert.

Of course, the “all at once way” using the walrus to combine the assertion with business logic all inside the `assert` is fundamentally broken, as the business logic will be skipped on `-O` and the code will `NameError`.

---

<div class="post-metadata">

**Author:** ![CAM-Gerlach](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cam-gerlach/32/3688_2.png) [@CAM-Gerlach](https://discuss.python.org/u/CAM-Gerlach)\
**Post date:** [April 27, 2025, 11:06am UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/17 "2025-04-27T11:06:25Z")

</div>

Seems a bit abusive, since `lambda`s being limited to a single line is an intentional design choice to discourage non-trivial anonymous functions, and complex, “heavy-lifting” lambdas subvert their core benefit/use case (small inline functions defined and used in a single line) relative to a more readable and reusable named function.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [April 27, 2025, 12:13pm UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/18 "2025-04-27T12:13:15Z")

</div>

> [@CAM-Gerlach](#):
>
> I’d normally agree with you that `assert` abuse should be avoided, but if as the user asserts (pun intended) this is merely a safety check that is not required in production and can be skipped for performance reasons, then the “before the walrus” example is at least arguably a legitimate use of assert.

I agree, but I am also very much aware that what you intend TODAY might not be what happens TOMORROW. If you start with this:

```python
def frobnicate(stuff):
    assert (n := stuff.length()) >= 3, "Need at least three things"
    assert n < 10, "Can't have ten things"

```

then you have the risk that you subsequently do this:

```python
   ...
   more_stuff = [0] * n

```

without realising that you just made use of the assertion.

This might be a good use-case for an explicit `if __debug__ :` block. It has the same risk (since there’s no way to scope the variable to just the `if` block), but might be a bit clearer - in debug mode, do this, do this, do this, make these checks. Not sure what I’d do in production though, as I don’t tend to use assertions _at all_ - I prefer to have the vast majority of checks actually continue to happen in prod. Maybe that’s just cynicism, but I have been programming for a few decades, and I’ve learned not to trust myself 🙂

---

<div class="post-metadata">

**Author:** ![CAM-Gerlach](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cam-gerlach/32/3688_2.png) [@CAM-Gerlach](https://discuss.python.org/u/CAM-Gerlach)\
**Post date:** [April 27, 2025, 12:23pm UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/19 "2025-04-27T12:23:09Z")

</div>

> [@Rosuav](#):
>
> I agree, but I am also very much aware that what you intend TODAY might not be what happens TOMORROW. If you start with this:
> 
> ```python
> def frobnicate(stuff):
> assert (n := stuff.length()) >= 3, "Need at least three things"
> assert n < 10, "Can't have ten things"
> 
> ```
> 
> then you have the risk that you subsequently do this:
> 
> ```python
> ...
> more_stuff = [0] * n
> 
> ```

Right, which is exactly why in my quote I stated that only the user’s “before the walrus” example was arguably a legitimate use of assert (since only the actual check was affected, which they stated they would like to intentionally disable in production code with `-O` for perf reasons):

> [@hprodh](#):
>
> ```python
> def process_mix(data0, data1):
> assert data0.parameter == data1.parameter # safety check
> parameter = data0.parameter # parameter extraction
> ...
> 
> ```

while the “all-at-once” example using the walrus operator was fundamentally flawed as it also skips the `parameter` assignment that is presumably used in the business logic:

> [@hprodh](#):
>
> ```python
> def process_mix(data0, data1):
> assert (parameter := data0.parameter) == data1.parameter
> ...
> 
> ```

Perhaps I merely misunderstood which example you were critiquing, and we are in fact in violent agreement here 🙂

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [April 27, 2025, 12:24pm UTC](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906/20 "2025-04-27T12:24:34Z")

</div>

> [@CAM-Gerlach](#):
>
> Perhaps I merely misunderstood which example you were critiquing, and we are in fact in violent agreement here

Probably 🙂 We may be disagreeing only in the extent to which we think that this is a bad idea.

[Next page](https://discuss.python.org/t/is-the-walrus-operator-antipattern/87906.md?page=2)
