Assignment Expressions: The Walrus Operator
In this lesson, you’ll learn about the biggest change in Python 3.8: the introduction of assignment expressions. Assignment expression are written with a new notation (:=)
.This operator is often called the walrus operator as it resembles the eyes and tusks of a walrus on its side.
Assignment expressions allow you to assign and return a value in the same expression. For example, if you want to assign to a variable and print its value, then you typically do something like this:
>>> walrus = False
>>> print(walrus)
False
In Python 3.8, you’re allowed to combine these two statements into one, using the walrus operator:
>>> print(walrus := True)
True
>>> type(walrus)
<class 'bool'>
The assignment expression allows you to assign True
to walrus
, and immediately print the value. But keep in mind that the walrus operator does not do anything that isn’t possible without it. It only makes certain constructs more convenient, and can sometimes communicate the intent of your code more clearly.
One pattern that shows some of the strengths of the walrus operator is while
loops where you need to initialize and update a variable. For example, the following code asks the user for input until they type quit
:
# write_something.py
inputs = list()
current = input("Write something: ")
while current != "quit":
inputs.append(current)
current = input("Write something: ")
This code is less than ideal. You’re repeating the input()
statement, and somehow you need to add current
to the list before asking the user for it. A better solution is to set up an infinite while
loop, and use break
to stop the loop:
# write_something.py
inputs = list()
while True:
current = input("Write something: ")
if current == "quit":
break
inputs.append(current)
This code is equivalent to the code above, but avoids the repetition and somehow keeps the lines in a more logical order. If you use an assignment expression, then you can simplify this loop further:
# write_something.py
inputs = list()
while (current := input("Write something: ")) != "quit":
inputs.append(current)
This moves the test back to the while
line, where it should be. However, there are now several things happening at that line, so it takes a bit more effort to read it properly. Use your best judgement about when the walrus operator helps make your code more readable.
PEP 572 describes all the details of assignment expressions, including some of the rationale for introducing them into the language, as well as several examples of how the walrus operator can be used. The Python 3.8 documentation also includes some good examples of assignment expressions.
Here are a few resources for more info on using bpython, the REPL (Read–Eval–Print Loop) tool used in most of these videos:
00:00 In this video, you’ll learn about what’s being called the walrus operator. One of the biggest changes in Python 3.8 is the introduction of these assignment expressions. So, what does it do?
00:12
Well, it allows the assignment and the return of a value in the same expression, using a new notation. On the left side, you’d have the name of the object that you’re assigning, and then you have the operator, a colon and an equal sign (:=
), affectionately known as the walrus operator as it resembles the eyes and tusks of a walrus on its side.
00:32 And it’s assigning this expression on the right side, so it’s assigning and returning the value in the same expression. Let me have you practice with this operator with some code.
00:44
Throughout this tutorial, when I use a REPL, I’m going to be using this custom REPL called bpython
. I’ll include links on how to install bpython
below this video.
00:53
So, how do you use this assignment operator? Let me have you start with a small example. You could have an object named walrus
and assign it the value of False
, and then you could print it. In Python 3.8, you can combine those two statements and do a single statement using the walrus operator. So inside of print()
, you could say walrus
, the new object, and use the operator, the assignment expression :=
, and a space, and then say True
. That’s going to do two things. Most notably, in reverse order, it returned the value True
. And then it also assigned the value to walrus
, and of course the type of 'bool'
.
01:38 Keep in mind, the walrus operator doesn’t do anything that isn’t possible without it. It only makes certain constructs a bit more convenient, and can sometimes communicate the intent of your code more clearly.
01:48
Let me show you another example. It’s a pattern that shows some of the strengths of the walrus operator inside of while
loops, where you need to initialize and update a variable. For example, create a new file, and name it write_something.py
. Here’s write_something.py
.
02:09
It starts with inputs
, which will be a list. So create a list called inputs
.
02:16
Into an object named current
, use an input()
statement. The input()
statement is going to provide a prompt and read a string in from standard input. The prompt will be this, "Write something: "
.
02:28
So when the user inputs that, that’ll go into current
. So while current != "quit"
—if the person has not typed quit
yet—you’re going to take inputs
and append the current
value.
02:44
And then here, you’re asking to "Write something: "
again.
02:50 Down here at my terminal, after saving—let’s see, make sure you’re saved. Okay. Now that’s saved.
03:00
So here, I could say, Hello
, Welcome
, and then finally quit
, which then would quit it. So, this code isn’t ideal.
03:08
You’re repeating the input()
statement twice, and somehow you need to add current
to the list before asking the user for it. So a better solution is going to be to set up maybe an infinite while
loop, and then use a break
to stop the loop. How would that look?
03:22
You’re going to rearrange this a little bit. Move the while
loop up, and say while True:
03:35
and here say if current == "quit":
then break
. Otherwise, go ahead and append it. So, a little different here, but this is a while
loop that’s going to continue as long as it doesn’t get broken out of by someone typing quit
. Okay.
03:53 Running it again. And there, you can see it breaking out. Nice. So, that code avoids the repetition and kind of keeps things in a more logical order, but there’s a way to simplify this to use that new assignment expression, the walrus operator. In that case, you’re going to modify this quite a bit.
04:17
Here you’re going to say while
, current
and then use that assignment operator (:=
) to create current
.
04:23
But also, while doing that, check to see that it’s not equal to "quit"
. So here, each time that assigns the value to current
and it’s returned, so the value can be checked.
04:35
So while
, current
, assigning the value from the input()
, and then if it’s not equal to "quit"
, you’re going to append current
. Make sure to save.
04:42 Run the code one more time.
04:47
And it works the same. This moves that test all the way back to the while
line, where it should be. However, there’s a couple of things now happening all in one line, and that might take a little more effort to read what’s happening and to understand it properly.
05:00 There are a handful of other examples that you could look into to learn a little more about assignment expressions. I’ll include a link to PEP 572, and also a link to the Python docs for version 3.8, both of which include more code examples.
05:14 So you need to use your best judgment as to when this operator’s going to make your code more readable and more useful. In the next video, you’ll learn about the new feature of positional-only arguments.
Geir Arne Hjelle RP Team on Dec. 4, 2019
My two cents about list()
vs []
(I wrote the original article this video series is based on):
- I find spelling out
list()
to be more readable and easier to notice and interpret than[]
[]
is several times faster thanlist()
, but we’re still talking nanoseconds. On my computer[]
takes about 15ns, whilelist()
runs in 60ns. Typically, lists are initiated once, so this does not cause any meaningful slowdown of code.
That said, if I’m initializing a list with existing elements, I usually use [elem1, elem2, ...]
, since list(...)
has different–and sometimes surprising–semantics.
Jason on April 3, 2020
Sorry for my ignorance, did the the standard assignment = operator work in this way? I don’t understand what has been gained from adding the := operator. If anything I think it will allow people to write more obfuscated code. But minds better than mine have been working on this, so I’ll have to take their word it is an improvement.
Jason on April 3, 2020
As for the discussion on whether [] is more readable than list(). I’d never seen list() before, so to me [] is better. I’ve only just come over from the dark 2.7 side so maybe it’s an old python programmer thing?
Oh I checked the operation on the assignment operator. I was obviously wrong. lol Still I think the existing operator could’ve been tweaked to do the same thing as := … I’m still on the fence about that one.
gedece on April 3, 2020
you are right in that the existing operator could have worked, but it can lead to something unexpected.
if you do something like
if (newvar = somevar): it gives a traceback, because you are supposed to use == for comparations.
So if you use the normal operator for this, then that expression is valid and you’ll be hard pressed to realize the mistake.
It then makes complete sense to use a different operator as that helps to clarify intent in code.
Jason on April 6, 2020
Yes, I’ve accidentaly done that in other languages before and it can be a difficult to “see” bug.
varelaautumn on Sept. 26, 2020
I watched this earlier today and now tonight I just can’t stop myself from throwing these walrus operators everywhere.
(I’m new and learning so these are just personal fooling around programs)
For example I have this function which cycles through a bunch of other very simple parsing functions that check if my input string is valid in the context of the game state. If the string doesn’t pass one of these parsers it returns a string with an error message such as “Input must be less than 5 characters”. And then the parse_input function returns that error string.
I mean it’s not a huge change, but it saves an extra call of the function, and I feel like it makes it much more readable.
from this:
def parse_input(string: str, parsers: Tuple[Callable]) -> str or None:
for parser in parsers:
if parser(string):
return parser(string)
to this:
def parse_input(string: str, parsers: Tuple[Callable]) -> str or None:
for parser in parsers:
if error := parser(string):
return error
I’m not sure if this other case might be considered abuse of the walrus operator, but I decided to use it twice in one line.
This function repeatedly asks for input. If the input does not pass the parser functions, then the error will be returned and printed out in the while loop. Otherwise the input was valid and it gets returned.
def user_input(parsers: Tuple[Callable]) -> str:
while error := parse_input(input_string := input('>>> '), parsers):
print(f"Error: '{input_string}' is not a valid input. {error}")
return input_string
### Here's an example of how it'd look in action:
# > "What is your name?"
# > >>> a
# > "Error: 'a' is not a valid input. Input must be at least 2 characters long."
# > >>> 55334
# > "Error: '55334' is not a valid input. Input must be alphabetical."
# > >>> Autumn
# > Autumn
I’m able to pass my input into a function and check the result of that function all while retaining my input and the return of the function as their own variables to be used in the next line.
I think the walrus operator helped me put all the relevant details on the three lines. Like if you just read the first words of each line, it basically says “while error, print error, else return input_string.” I don’t see how I could have done that without this cool walrus operator so I’m really appreciative for this video you made! I’ve been converted to a strong believer in the walrus operator.
Geir Arne Hjelle RP Team on Sept. 26, 2020
@varelaautumn Nice examples, thanks for sharing!
I agree that the walrus operator will not revolutionize your code, but it can bring these sorts of small improvements that add up in the long run.
Become a Member to join the conversation.
rajeshboyalla on Dec. 4, 2019
Why do you use
list()
to initialize a list rather than using[]
?