The Walrus Operator (:=): Assignment Expressions in Python
:=assigns a value to a name and produces that value as the result of an expression, in one place.- It is most useful where a value is needed both to make a decision and to use afterward — avoiding computing or calling something twice.
- Introduced in Python 3.8, it does not replace
=; ordinary assignment still needs the regular statement form. - The expression being assigned generally needs parentheses when used inside another expression, such as an f-string or a comprehension condition.
Statement vs. expression assignment
Ordinary assignment with = is a statement in Python, not an expression — it does not produce a value that can be used inside a larger expression, and writing if (x = 5): is a syntax error. This is a deliberate design choice that avoids a classic C-family bug: accidentally typing if (x = 5) when you meant the comparison if (x == 5).
The walrus operator, :=, adds a controlled way to assign as an expression, so the assigned value is available both as a name and as the expression's result:
print(n := 5) # prints 5, and n is now bound to 5
print(n) # 5
Avoiding repetition in while loops
A very common pattern before the walrus operator was reading a value, checking it, and reading it again inside the loop — duplicating the read call:
line = input("Enter a line ('quit' to stop): ")
while line != "quit":
print(f"You said: {line}")
line = input("Enter a line ('quit' to stop): ")
The input() call appears twice, once before the loop and once inside it, purely to prime the condition. With :=, the read and the check happen in one place:
while (line := input("Enter a line ('quit' to stop): ")) != "quit":
print(f"You said: {line}")
The duplicated priming call is gone, and there is exactly one place in the code that calls input(), which is one fewer place a future edit could update inconsistently.
Reusing a computed value in a comprehension
Comprehensions sometimes need to filter on a computed value and then use that same computed value in the output, which previously meant computing it twice:
values = [1, 2, 3, 4, 5, 6, 7, 8]
# without walrus: compute the square twice
result = [v * v for v in values if v * v > 10]
# with walrus: compute it once, filter and reuse the same result
result = [square for v in values if (square := v * v) > 10]
print(result) # [16, 25, 36, 49, 64]
For a cheap operation like squaring, the duplication barely matters. For an expensive function call — a database lookup, a regex match, a network request — avoiding the second call can matter a great deal, both for performance and for correctness if the call has side effects.
Assigning inside an if condition
The same pattern shows up with regular expressions and dictionary lookups, where you need to know whether something matched before using the match result:
import re
text = "Order #4471 shipped"
if (match := re.search(r"#(\d+)", text)):
print(f"Found order number: {match.group(1)}")
else:
print("No order number found")
Without :=, this typically required either calling re.search twice (once to check, once to use) or assigning to a name on the line before the if, splitting one logical step across two lines. The walrus operator lets the check and the binding live together on the same line.
Syntax rules and required parentheses
:= can only appear where an expression is expected, and Python's grammar requires parentheses around it in most contexts to avoid ambiguity with ordinary assignment:
x = 5 # ordinary assignment statement, no parentheses
y = (x := 6) # assignment expression, used as part of a larger statement, needs parens here
Top-level, unparenthesized x := 5 is not valid on its own line as a statement — the walrus operator is for using an assignment as part of some other expression or statement (an if, a while, a comprehension, an f-string), not for replacing plain assignment.
When to leave it out
The walrus operator is a tool for removing genuine duplication, not a style to reach for by default. If a comprehension or condition is already clear without it, forcing an assignment expression in usually makes the line harder to read rather than easier. A reasonable rule of thumb: use := when it eliminates a real second computation or a second line that existed purely to prime a value; skip it when the code was already simple and the walrus would only make the line more compact at the cost of being less obvious at a glance.
It is also worth remembering that a name bound with := follows normal scoping rules, and inside a comprehension it leaks into the enclosing scope in a way that comprehension loop variables themselves do not:
values = [1, 2, 3]
result = [y for x in values if (y := x * 2) > 2]
print(y) # 4 -- y is visible here, unlike x
A comprehension's own loop variable (x here) stays private to the comprehension, but a name introduced with := escapes into the surrounding function or module scope, exactly as if it had been assigned with a plain = statement outside the comprehension. That difference rarely causes problems in practice, but it is a detail worth knowing before relying on a walrus-bound name immediately after a comprehension finishes.