Walrus operator (:=) gotchas
The gotcha
The walrus operator (PEP 572, Python 3.8+) is an assignment expression — it returns the assigned value. It has lower precedence than most operators, requires parens in many contexts, and is forbidden at the top level of a statement.
Minimal repro
# Useful: avoid double-call
if (n := len(data)) > 10:
print(f"too long: {n} items")
# Useful: read-and-test loop
while (chunk := f.read(1024)):
process(chunk)
# Forbidden: top-level assignment expression
x := 5 # SyntaxError
(x := 5) # works inside parens
# Precedence trap:
y = x := 5 # SyntaxError
y = (x := 5) #
# Inside f-strings (3.8+ only with care):
print(f"{(n := 42)}") # works in 3.12+, was a parse trap earlier
Why it happens
:= is intentionally awkward at the top level to discourage replacing =. Its precedence is below ,, so a, b := 1, 2 is parsed as a, (b := 1), 2 — a tuple, not an assignment.
It’s an expression (evaluates to the assigned value), unlike = which is a statement. That’s why you can use it inside if, while, comprehensions:
[y for x in data if (y := f(x)) is not None]
How to avoid
- Use parens generously when in doubt — they disambiguate.
- Don’t use
:=where=works fine. It’s for condense-the-test and assign-inside-comprehension cases. - For simple “assign and use” inside a chain of statements, regular
=on its own line is clearer:
# Less clear:
if (data := fetch()) is not None and (n := len(data)) > 0: ...
# Clearer:
data = fetch()
if data is not None and len(data) > 0: ...
Interview angle
“Where would you use the walrus operator?” Good answer: regex matches (if (m := pattern.match(s)):), file-reading loops, expensive computations you want to test and reuse.