The Controversy Behind The Walrus Operator in Python

The Controversy Behind the Walrus Operator in Python Featured Image

If you haven’t heard, Python 3.8 features a rather controversial new operator called the walrus operator. In this article, I’ll share some of my first impressions as well as the views from all sides. Feel free to share some of your thoughts as well in the comments.

Table of Contents

Understanding the Walrus Operator

Recently, I was browsing, and I found a really cool article by Jason McDonaldOpens in a new tab. which covered a new feature in Python 3.8, the walrus operator. If you haven’t seen the operator, it looks like this: :=.

In this article, Jason states that the new operator “allows you to store and test a value in the same line.” In other words, we can compress this:

nums = [87, 71, 58]
max_range = max(nums) - min(nums)
if max_range > 30:
  # do something

Into this:

nums = [87, 71, 58]
if (max_range := max(nums) - min(nums)) > 30:
  # do something

In this example, we saved a line because we moved the assignment into the condition using the walrus operator. Specifically, the walrus operator performs assignment while also returning the stored value.

In this case, max_range will store 29, so we can use it later. For example, we might have a few additional conditions which leverage max_range:

nums = [87, 71, 58]
if (max_range := max(nums) - min(nums)) > 30:
  # do something
elif max_range < 20:
  # do something else

Of course, if you’re like me, you don’t really see the advantage. That’s why I decided to do some research.

First Impressions

When I first saw this syntax, I immediately thought “wow, this doesn’t seem like a syntax that meshes well with the Zen of Python.” In fact, after revisiting the Zen of PythonOpens in a new tab., I think there are several bullet points this new syntax misses.

Beautiful Is Better Than Ugly

While beauty is in the eye of the beholder, you have to admit that an assignment statement in the middle of an expression is kind of ugly. In the example above, I had to add an extra set of parentheses to make the left expression more explicit. Unfortunately, extra parentheses reduce the beauty quite a bit.

Sparse Is Better than Dense

If the intent of the walrus operator is to compress two lines into one, then that directly contradicts “sparse is better than dense.” In the example I shared above, the first condition is fairly dense; there’s a lot to unpack. Wouldn’t it always make more sense to place the assignment on a separate line?

If you’re looking for a good example of a feature that compresses code, take a look at the list comprehension. Not only does it reduce nesting, but it also makes the process of generating a list much simpler. To be honest, I don’t get that vibe with the walrus operator. Assignment is already a pretty easy thing to do.

In the Face of Ambiguity, Refuse the Temptation to Guess.

In the example above, I introduced parentheses to make the condition more explicit. Had I left out the parentheses, it becomes a little more difficult to parse:

 if max_range := max(nums) - min(nums) > 30:

In this case, we have several operators on a single line, so it’s unclear which operators take precedence. As it turns out, the arithmetic comes first. After that, the resulting integer is compared to 30. Finally, the result of that comparison (False) is stored in max_range and returned. Would you have guessed that when looking at this line?

To make matters worse, the walrus operator makes assignment ambiguous. In short, the walrus operator looks like a statement, but it behaves like an expression with side effects. If you’re unsure why that might be an issue, check out my article on the difference between statements and expressions.

There Should Be One—and Preferably Only One—Obvious Way to Do It.

One of the interesting things about this operator is that it now introduces a completely new way to perform assignment. In other words, it directly violates the “there should be only way way to do it” rule.

That said, I’m a little bit on the fence with this one because the new operator is more explicit. In other words, it differentiates the intent behind := and =. In addition, it reduces potential bugs related to confusing = and == in conditions.

Likewise, as far as I can tell, you can’t just use the walrus operator in all the same places you would use assignment. In fact, they’re completely different operators. Unfortunately, nothing is really stopping you from doing something like this:

(x := 5)

I don’t know why you would ever do this, but it’s now very legal code. Luckily, PEP 572 prohibits itOpens in a new tab.. Of course, that doesn’t stop code like this from appearing in the wild. In fact, the documentation lists a handful of ways the new syntax can be abused. That’s not a good sign!

If the Implementation Is Hard to Explain, It’s a Bad Idea

At this point, I sort of drew the line with this new feature. As I dug around to read others’ opinions on the subject, I found the following gold nugget:

This feels very Perl-y in the example given, in that it requires that you know what yet another operator means to read code that uses it. Since Python is supposed to be “executable pseudocode” (roughly), this kind of new operator might increase the amount of learning that a beginner has to do to read others’ code. I hope that this decision does not pave the way for more like it, because it would make Python code much less readable to someone who hasn’t studied the new operators yet.

snazzOpens in a new tab., 2019

That’s when I realized why I love Python so much. It’s just so damn easy to read. At this point, I really feel like the addition of this operator was a mistake.


As with anything, I hate to form an opinion without really digging into the topic, so I decided to hear from the folks who were excited about this feature. To my surprise, I found a lot of cool examples.

Loop Variable Updates Are Easy

By far, the strongest case for the new walrus operator is in while loops. Specifically, I liked the example by Dustin Ingram which leveraged the operator to remove duplicate lines of code. For example, we can convert this (sourceOpens in a new tab.):

chunk =
while chunk:
  chunk =

Into this:

while chunk :=

By introducing the walrus operator, we remove a duplicate line of code. Now, every time the loop iterates, we automatically update chunk without having to initialize it or update it explicitly.

Seeing this example is enough for me to see the value in the walrus operator. In fact, I’m so impressed by this example that it made me wonder where else this could be used to improve existing code.

That said, I did dig around, and some folks still felt like this was a bad example. After all, shouldn’t file reading support an iterable? That way, we could use a for loop, and this wouldn’t be an issue at all. In other words, isn’t the walrus operator just covering up for bad library design? Perhaps.

List Comprehensions Get a New Tool

As an avid list comprehension enthusiast, I’ve found that the walrus operator can actually improve efficiency by allowing us to reuse calculations. For example, we might have a comprehension which looks like this:

[determinant(m) for m in matrices if determinant(m) > 0]

In this example, we build up a list of determinants from a list of matrices. Of course, we only want to include matrices whose determinants are greater than zero.

Unfortunately, the determinant calculation might be expensive. In addition, if we have a lot of matrices, calculating the determinant twice per matrix could be costly. As a result, we might want to write a more complex expression to reduce the number of determinant calculations (courtesy of Lorem Ipsum):

Legacy Comment on the Walrus Operator

Even better, we can now leverage the walrus operator:

[d for m in matrices if (d := determinant(m)) > 0]

Now, we only calculate the determinant once for each matrix. How slick is that?


Beyond the two examples above, I’ve seen a few other examples including pattern matching, but I don’t really have an appreciation for it. Honestly, the other examples just seem kind of niche.

For instance, PEP 572Opens in a new tab. states that the walrus operator helps with saving expensive computations. Of course, the example they provide is with constructing a list:

[y := f(x), y**2, y**3]

Here, we have a list that looks like this:

[y, y**2, y**3]

In other words, what’s stopping us from declaring y on a separate line?

y = f(x)
[y, y**2, y**3]

In the list comprehension example above, I get it, but here I don’t. Perhaps there’s a more detailed example which explains why we’d need to embed an assignment statement in list creation. If you have one, feel free to share it in the comments.


Now that I’ve had a chance to look at the new walrus operator more or less objectively, I have to say that I think my first impressions still stand, but I’m willing to be persuaded otherwise.

After seeing a few solid examples, I was still really skeptical, so I decided to take a look at the rationale behind the operator in PEP 572Opens in a new tab.. If you get a chance, take a look at that document because it’s enormous. Clearly, this decision was well thought out. My only fear is that the authors were persuaded to include the feature by shear sunk cost fallacyOpens in a new tab., but who knows.

If you read through PEP 572, you’ll see 79 code blocks across the entire page. To me, that’s just a ridiculous amount of examples. To make matters worse, a large portion of the examples show edge cases where the operator won’t work or wouldn’t be ideal rather than where it would provide an edge. For instance, take a look at some of these examples:

x = y = z = 0  # Equivalent: (z := (y := (x := 0)))
x = 1, 2  # Sets x to (1, 2)
(x := 1, 2)  # Sets x to 1
total += tax  # Equivalent: (total := total + tax)

That said, the authors did go as far as to provide some examples from their reworked standard libraryOpens in a new tab.. Of course, these examples are much larger, so I won’t share them here. However, you’re welcome to take a peek.

Personally, I think the examples linked above illustrate the advantage of the walrus operator much better than some of the cases I shared in the counterpoint section. Specifically, any time the walrus operator removes duplicate or nested code, I’m happy with it. Otherwise, it seems to have very few obvious use cases.

My worry is that adding a new operator adds unnecessary complexity to the language, and I’m not convinced that the pros outweigh the cons. At any rate, I trust the decision of the team that put it together, and I’m excited to see how the community uses it!


With all that said, thanks again for showing your support and checking out my work. If you’re new here, I’d appreciate it if you hopped on my mailing listOpens in a new tab. or even joined me on PatreonOpens in a new tab.. If you do decide to lay down some cash, there’s a ton in it for you including having an article written about youOpens in a new tab. and gaining access to premium articles.

While you’re here, you might benefit from some additional Python resources courtesy of Amazon:

Alternatively, you’re welcome to stick around and check out some of my other Python articles:

As always, thanks for stopping by! See you back soon.

Jeremy Grifski

Jeremy grew up in a small town where he enjoyed playing soccer and video games, practicing taekwondo, and trading Pokémon cards. Once out of the nest, he pursued a Bachelors in Computer Engineering with a minor in Game Design. After college, he spent about two years writing software for a major engineering company. Then, he earned a master's in Computer Science and Engineering. Today, he pursues a PhD in Engineering Education in order to ultimately land a teaching gig. In his spare time, Jeremy enjoys spending time with his wife, playing Overwatch and Phantasy Star Online 2, practicing trombone, watching Penguins hockey, and traveling the world.

Recent Posts