It’s interesting to share an example of using walrus operators that I saw on Twitter, the code looks like this:

1
2
3
4
>>> (a := 1)
>>> (a, b := 2, 3)
>>> print(f'a={a}, b={b}')
a=1, b=2

The sentence (a, b := 2, 3) is particularly confusing, especially if you’ve written Go, and it’s likely that you intuitively think this expression is fine. But you can see through the output that it doesn’t match expectations at all, so what is wrong? Let’s take our time and analyze it.

Why parentheses

This topic expands a lot and involves Python syntax, so let’s dive in step by step.

The Difference Between Expressions and Statements

A statement is one or more lines of code, and is a separate unit of the program. Expressions are special statements that can only contain identifiers (letters, numbers, underscores, etc.), literals (Python’s built-in constant types, such as strings, numbers, floating point numbers), and operators (add, subtract, multiply, divide, greater-than, less-than, different-or, remainder, etc.):

1
2
1 + 2  # 表达式
a = 1 + 2  # 语句

As in the example above, 1 + 2 is essentially a value (equal to 3), a = 1 + 2 is just code logic, no value, just an assignment statement.

Assignment expressions and assignment statements

Let’s look at an example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
In : x = 1

In : x
Out: 1

In : (y := 2)
Out: 2

In : y
Out: 2

where x = 1 is an assignment statement, which sets a specific value (1) to a specific storage address, which is marked with a specific variable name (x). (y := 2) is an assignment expression, which adds the step value to the assignment statement, which returns the result (2), so you can see the output Out: 2.

It is a syntax error not to add parentheses:

1
2
3
4
5
In : y := 2
  File "<ipython-input-8-b0043aac4290>", line 1
    y := 2
      ^
SyntaxError: invalid syntax

This is because in Python, assignment expressions and assignment statements are different syntaxes, and the following 2 ways are the correct syntax:

  1. assignment expressions use the := operator
  2. assignment statements use the = operator

Similarly, the following code is also syntactically incorrect:

1
2
3
4
5
In : (y = 2)
  File "<ipython-input-13-a73f2c6719f5>", line 1
    (y = 2)
       ^
SyntaxError: invalid syntax

So you cannot directly try to replace the = operator with the := operator, you must add a parenthesis to assign a single value using an assignment expression.

The problem of converting assignment statements into expressions

We said that assignment expressions and assignment statements are syntactically different. The reason for this design is that converting an existing assignment statement into an expression is prone to bugs, which are exposed in C. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>

int main() {
  int x = 3, y = 8;

  if (x = y) {
    printf("x and y are equal (x = %d, y = %d)", x, y);
  }
  return 0;
}

This is a compliant code, but (x = y) causes x to be reassigned to the value of y causing this judgment to be true and the output to be x and y are equal (x = 8, y = 8). The reason for this is that the code does not use the comparison operator ==, which is a hidden error that is now explicitly thrown by programming languages like Python or Go.

1
2
3
4
5
6
7
8
In : x = 1
...: y = 2
...: if x = y:
...:     print('equal')
  File "<ipython-input-5-5f6807f1b35f>", line 3
    if x = y:
         ^
SyntaxError: invalid syntax

It is possible (though not necessary) to achieve this logic with the correct walrus operator:

1
2
3
4
5
6
In : x = 1
...: y = 2
...: if (x := y):
...:     print(f'equal: {x=} {y=}')
...:
equal: x=2 y=2

Why did you write the sentence (a := 1)?

The answer is right here, and this added point is the problem with this confusing code. It’s really simple, try removing it:

1
2
3
4
5
6
7
In : (a, b := 2, 3)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-83c3cb14fd64> in <module>
----> 1 (a, b := 2, 3)

NameError: name 'a' is not defined

This means that the code itself is not written correctly. In fact, this statement represents a tuple with three elements, a, b := 2, 3. Here it says that a is not defined, but of course, it has never been assigned a. If you execute it in IPython, you can understand it.

1
2
3
4
5
In : (a := 1)  # 相当于`a = 1`
Out: 1  # 赋值a=1,并且返回这个值(1)

In : (a, b := 2, 3)
Out: (1, 2, 3)

The output is actually the result of returning the input data, so (a, b := 2, 3) returns a tuple, the first element a is the result of the previous assignment, the second element is the result of the walrus operator, and the third is the literal 3.