🐍 Python Course · Stage 2 · Lesson 23 of 89 · Walrus Operator
Course Overview →

🔵 Read Beginner then Intermediate tabs. Visit Expert when ready.

← Exception Hierarchy File I/O →
thecodex.expert · The Codex Family of Knowledge
Python

The Walrus Operator (:=) in Python

The walrus operator := assigns a value to a variable as part of a larger expression — letting you capture and test a value in a single step.

Python 3.13 docs.python.org Last verified:
Canonical Definition

The walrus operator (:=), formally an assignment expression, was introduced by PEP 572 in Python 3.8. Unlike the = statement, := is an expression that both assigns to a name and evaluates to the assigned value, so it can be used inside conditions, comprehensions, and other expressions.

🟩 Beginner

Assign inside an expression

What you will learn: how := assigns a value as part of a larger expression, letting you capture and test a value in one step.

How to read this tab: Remember := needs parentheses in most places, and cannot replace = at the top level.

⏱ 20 min📄 1 section🔶 Prerequisite: Control Flow & Loops
The idea

Normally = is a statement on its own line. The walrus := lets you assign a value inside a bigger expression — for example, computing a value and testing it in the same if. The name comes from its resemblance to a walrus's eyes and tusks.

Walrus needs parentheses, and cannot replace = at top level. Write if (n := len(x)) > 10: with parentheses. A bare n := 5 on its own line is a syntax error — use normal = there. The walrus is only for when you are inside a larger expression.

Assigning inside an expression

The walrus operator captures a value into a variable at the same moment you use that value. This removes the common pattern of computing something, then immediately testing it on the next line.

Pythonwalrus_basic.py
# WITHOUT walrus — compute, then test on separate lines
name = input("Name: ")
if len(name) > 50:
    print("Too long")

# WITH walrus — assign and test in one expression
if (length := len(name)) > 50:
    print(f"Too long: {length} chars")
# 'length' is now available for use afterwards too

# Useful when you need the value AND the test
import re
text = "order #12345"
if (match := re.search(r"#(\d+)", text)):
    print(f"Order number: {match.group(1)}")   # 12345
# Without walrus you'd call re.search twice or use a temp variable

# Avoid recomputing an expensive value
data = [1, 2, 3, 4, 5]
if (total := sum(data)) > 10:
    print(f"Sum {total} exceeds limit")   # reuses total, no recompute
Walrus needs parentheses in most places

To avoid ambiguity, := usually must be wrapped in parentheses: if (n := len(x)) > 10:. A bare := at statement level (n := 5 on its own line) is a syntax error — use the normal = there. The walrus is for when you are inside a larger expression.

✅ Beginner tab complete

  • I can use := to assign and test in one if statement
  • I know := requires parentheses in most contexts
  • I know := is an expression while = is a statement
  • I know a bare := at top level is a syntax error

Continue to File I/O →

🔵 Intermediate

while loops and comprehensions

What you will learn: the classic while-loop read pattern, and using := in comprehensions to compute a value once instead of twice.

How to read this tab: The file-chunk-reading while loop is the canonical walrus example — learn it.

⏱ 20 min📄 2 sections🔶 Prerequisite: Beginner tab

The canonical pattern: read once, in the condition. while (chunk := f.read(8192)): reads until empty, with no duplicated read call before and inside the loop. This is the example PEP 572 was largely designed for.

The classic use: while loops reading input

The walrus operator's most celebrated use is collapsing the "read, test, process, read again" loop pattern into a single clean line — eliminating the duplicated read call.

Pythonwalrus_loops.py
# WITHOUT walrus — the read appears twice (before loop AND inside)
line = input("> ")
while line != "quit":
    print(f"You said: {line}")
    line = input("> ")          # duplicated read — easy to forget

# WITH walrus — read once, in the condition
while (line := input("> ")) != "quit":
    print(f"You said: {line}")

# Reading a file in fixed-size chunks — a canonical example
with open("big.bin", "rb") as f:
    while (chunk := f.read(8192)):    # read until empty bytes
        process(chunk)

# Consuming from a queue until empty
import queue
q = queue.Queue()
# ... fill q ...
while not q.empty():
    item = q.get()
    process(item)
💡

Walrus avoids double computation in comprehensions. [y for x in data if (y := f(x)) > 0] calls f once per item; the naive version [f(x) for x in data if f(x) > 0] calls it twice. But remember the walrus name escapes into the enclosing scope.

In comprehensions — compute once, use twice

Inside a comprehension, the walrus lets you compute a value once and use it both in the filter condition and the output expression — avoiding a double computation.

Pythonwalrus_comprehension.py
def expensive(x):
    # imagine this is slow
    return x * x - 10

# WITHOUT walrus — expensive() called TWICE per item
result = [expensive(x) for x in range(10) if expensive(x) > 0]

# WITH walrus — expensive() called ONCE per item
result = [y for x in range(10) if (y := expensive(x)) > 0]
print(result)   # [6, 15, 26, 39, 54, 71]

# Capture intermediate values while filtering
data = ["1,2", "3,4", "bad", "5,6"]
parsed = [
    (a, b)
    for item in data
    if len(parts := item.split(",")) == 2
    and parts[0].isdigit()
    for a, b in [parts]
]

# Walrus scope in comprehensions LEAKS to the enclosing scope
# (unlike the loop variable, which does not)
nums = [y := x + 1 for x in range(3)]
print(y)    # 3 — y escaped the comprehension (last assigned value)
Commonly confused
:= vs =. = is a statement; it cannot appear inside an if or comprehension. := is an expression; it can. You cannot use := as a plain top-level assignment (x := 5 alone is a syntax error) — use = there.
Walrus variables leak from comprehensions. A normal comprehension loop variable does not escape, but a name bound with := inside a comprehension binds in the enclosing scope. This is intentional (PEP 572) but surprising.

✅ Intermediate tab complete

  • I can write while (line := input()) != "quit"
  • I can read file chunks with while (chunk := f.read(n))
  • I can use := in a comprehension to avoid computing a value twice
  • I know walrus names leak from comprehensions into the enclosing scope

Continue to File I/O →

🔴 Expert

Scope rules and prohibited forms

What you will learn: the comprehension-scope exception, the forms PEP 572 prohibits, and the readability guidance.

How to read this tab: Read for the precise rules — especially that walrus binds to the containing scope, not the comprehension.

⏱ 20 min📄 1 section🔶 Prerequisite: After Stage 2

Scoping rules, prohibited forms, and readability

PEP 572 specifies precise rules for assignment expressions. The bound name belongs to the containing scope, not any comprehension it appears in — the one deliberate exception to the rule that comprehensions have their own scope. Several forms are explicitly prohibited to prevent confusing or redundant code: you cannot use := at the top level of an expression statement, cannot assign to attributes or subscripts (obj.x := 1 is illegal), and cannot mix it with = on the same target.

Pythonwalrus_scope.py
# Comprehension scope exception — y binds OUTSIDE the comprehension
total = 0
values = [total := total + x for x in range(5)]
print(values)   # [0, 1, 3, 6, 10] — running total
print(total)    # 10 — the walrus name persists in enclosing scope

# Prohibited forms (all SyntaxError):
# x := 5                  # bare top-level — use x = 5
# obj.attr := 5           # cannot target an attribute
# d["key"] := 5           # cannot target a subscript
# x = (y := 5) = 3        # cannot chain with =

# Legitimate advanced use: avoid redundant work in any() / all()
lines = ["", "  ", "hello", "world"]
# Find first non-blank line AND keep it
if any((stripped := ln.strip()) for ln in lines):
    pass  # 'stripped' holds the LAST evaluated value (short-circuit aware)

# Use in f-strings for debugging (3.8+) combined with walrus
import math
r = 5
print(f"{(area := math.pi * r * r) = :.2f}")   # area = 78.54
print(area)   # 78.539... — still available

The PEP's stated motivation is to reduce a specific, common redundancy — computing a value, naming it, and immediately testing it — without encouraging dense one-liners. The style guidance from the PEP authors is explicit: use the walrus where it genuinely removes duplication or a throwaway temporary, and avoid it where a plain assignment on the preceding line would read more clearly. Overuse produces expressions that are hard to scan, which defeats the purpose.

✅ Expert tab complete

  • I know walrus binds in the containing scope, even inside a comprehension
  • I know obj.attr := and d[key] := are illegal
  • I use walrus only where it removes genuine duplication

Continue to File I/O →

Sources

1
Python Language Reference — Assignment expressions. docs.python.org/3/reference/expressions.html#assignment-expressions.
2
PEP 572 — Assignment Expressions. peps.python.org/pep-0572/.
3
Python What's New in 3.8 — Assignment expressions. docs.python.org/3/whatsnew/3.8.html.
Source confidence: High Last verified: Primary source: PEP 572 (Python 3.8)