|$ curl https://forge-ai.dev/api/markdown?path=docs/python/walrus
$cat docs/python-—-walrus-operator-(:=).md
updated Last week·16 min read·published

Python — Walrus Operator (:=)

PythonIntermediate🎯Free Tools
Introduction

The walrus operator := (introduced in Python 3.8, PEP 572) assigns a value to a variable as part of an expression. Before walrus, you had to assign a value on one line and use it on the next. Now you can do both in a single expression.

The name "walrus" comes from the operator's resemblance to a walrus with tusks: := looks like (: rotated 90 degrees.

Syntax Basics
syntax.py
Python
1# Before walrus — two separate statements
2data = get_data()
3if data:
4 process(data)
5
6# With walrus — assign and check in one line
7if (data := get_data()):
8 process(data)
9
10# The parenthesization matters
11# (x := value) — walrus expression
12# x = value — regular assignment (not an expression)
13
14# Basic syntax
15y = (n := 10) # y = 10, n = 10
16print(y, n) # 10 10
17
18# Works inside any expression
19a = (b := 5) + 3 # a = 8, b = 5
20print(a, b) # 8 5
21
22# Walrus returns the assigned value
23print((x := "hello")) # prints "hello"
24
25# Without walrus, you'd write:
26temp = compute_expensive()
27result = temp * 2
28
29# With walrus:
30result = (temp := compute_expensive()) * 2

info

Always use parentheses around walrus expressions when combining with other operators. Without parens, operator precedence can cause unexpected results.
While Loops

The most common walrus use case is reading data in a loop condition. Without walrus, you need a sentinel value and a duplicated condition check.

while_loops.py
Python
1# Without walrus — verbose sentinel pattern
2line = input("Enter text: ")
3while line != "quit":
4 print(f"You said: {line}")
5 line = input("Enter text: ")
6
7# With walrus — cleaner, no duplication
8while (line := input("Enter text: ")) != "quit":
9 print(f"You said: {line}")
10
11# Reading from a file line by line
12with open("data.txt") as f:
13 while (line := f.readline()):
14 process(line.strip())
15
16# Reading chunks from a stream
17buffer = b""
18while (chunk := stream.read(1024)):
19 buffer += chunk
20 if len(buffer) > 8192:
21 flush(buffer)
22 buffer = b""
23
24# Processing a queue until empty
25from collections import deque
26queue = deque([1, 2, 3, 4, 5])
27
28while (item := queue.popleft()):
29 print(f"Processing {item}")
30
31# Fibonacci with walrus
32a, b = 0, 1
33while (a := a + b) < 100:
34 print(a, end=" ")
35# Output: 1 2 3 5 8 13 21 34 55 89
If Conditions
if_conditions.py
Python
1# Cache expensive computation in an if-check
2import re
3
4# Without walrus
5match = re.search(r"\d{4}-\d{2}-\d{2}", text)
6if match:
7 date_str = match.group()
8 print(f"Found date: {date_str}")
9
10# With walrus
11if match := re.search(r"\d{4}-\d{2}-\d{2}", text):
12 print(f"Found date: {match.group()}")
13
14# Validate and process in one step
15user_input = " "
16if (cleaned := user_input.strip()):
17 process(cleaned)
18else:
19 print("Empty input")
20
21# Dictionary processing
22data = {"name": "Alice", "age": 30, "city": "NYC"}
23
24# Without walrus
25if "age" in data:
26 age = data["age"]
27 print(f"Age: {age}")
28
29# With walrus
30if (age := data.get("age")) is not None:
31 print(f"Age: {age}")
32
33# Chained checks
34config = {"debug": True, "log_level": "INFO"}
35
36if config.get("debug") and (level := config.get("log_level")):
37 print(f"Debug mode, level: {level}")
38
39# Short-circuit with walrus
40def expensive_check(x):
41 print(f"Checking {x}...")
42 return x > 0
43
44# Only runs expensive_check once — result reused in else
45if (result := expensive_check(42)):
46 print(f"Passed: {result}")
47else:
48 print(f"Failed: {result}") # uses cached result, no re-computation
List Comprehensions
comprehensions.py
Python
1# Walrus inside comprehensions — assign and filter in one pass
2
3# Without walrus — calls is_valid() twice
4items = [1, 2, 3, 4, 5, 6, 7, 8]
5filtered = [is_valid(x) for x in items if is_valid(x)]
6
7# With walrus — calls is_valid() once
8filtered = [y for x in items if (y := is_valid(x))]
9
10# Processing strings with regex in comprehension
11import re
12texts = ["hello world", "foo123bar", "no numbers", "abc42def"]
13
14# Extract numbers from texts
15numbers = [
16 int(m.group())
17 for text in texts
18 if (m := re.search(r"\d+", text))
19]
20print(numbers) # [123, 42]
21
22# Square root with threshold
23import math
24values = [1, 4, 9, 16, 25, 30, 49, 50]
25
26# Only keep values whose square root is an integer
27perfect = [
28 root
29 for x in values
30 if (root := math.isqrt(x)) ** 2 == x
31]
32print(perfect) # [1, 2, 3, 4, 5, 7]
33
34# Nested comprehension with walrus
35matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
36
37# Find all elements greater than their row average
38above_avg = [
39 (row_idx, val)
40 for row_idx, row in enumerate(matrix)
41 for val in row
42 if val > (avg := sum(row) / len(row))
43]
44
45# Dict comprehension with walrus
46raw = {"a": " 1 ", "b": " 2 ", "c": " 3 "}
47cleaned = {
48 k: (v := v.strip())
49 for k, v in raw.items()
50 if v.strip() # filter out empty after strip
51}
52
53# Set comprehension
54words = ["hello", "world", "python", "hi", "code"]
55short = {
56 word.upper()
57 for word in words
58 if len(word) <= (threshold := 4)
59}
60print(short) # {"HI", "CODE"}
Regex Matching
regex.py
Python
1import re
2
3# Parse log lines with walrus
4log_lines = [
5 "2024-01-15 10:30:00 ERROR Database connection failed",
6 "2024-01-15 10:31:00 INFO Request processed",
7 "2024-01-15 10:32:00 WARN High memory usage",
8 "Invalid log line",
9 "2024-01-15 10:34:00 ERROR Timeout exceeded",
10]
11
12pattern = re.compile(r"(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})\s+(\w+)\s+(.*)")
13
14# Without walrus — repeated match check
15errors = []
16for line in log_lines:
17 match = pattern.match(line)
18 if match:
19 date, time, level, msg = match.groups()
20 if level == "ERROR":
21 errors.append(f"{date} {time}: {msg}")
22
23# With walrus — inline match and extract
24errors = [
25 f"{date} {time}: {msg}"
26 for line in log_lines
27 if (match := pattern.match(line))
28 if (date, time, level, msg) == match.groups()
29 if level == "ERROR"
30]
31
32# Extract all emails from text
33text = "Contact alice@example.com or bob@test.org for info"
34emails = re.findall(r"[\w.]+@[\w.]+\.[a-z]+", text)
35
36# Find and process matches
37for email in (m := re.finditer(r"[\w.]+@([\w.]+)", text)):
38 domain = m.group(1)
39 print(f"Domain: {domain}")
40
41# Compile and match in one step
42if (match := re.fullmatch(r"\d{3}-\d{3}-\d{4}", "555-123-4567")):
43 print(f"Valid phone: {match.group()}")
44
45# Multi-pattern matching
46def parse_date(text):
47 for fmt, pattern in [
48 ("ISO", r"(\d{4})-(\d{2})-(\d{2})"),
49 ("US", r"(\d{2})/(\d{2})/(\d{4})"),
50 ("EU", r"(\d{2})\.(\d{2})\.(\d{4})"),
51 ]:
52 if (m := re.match(pattern, text)):
53 return fmt, m.groups()
54 return None, None
55
56fmt, parts = parse_date("2024-01-15")
57print(f"Format: {fmt}, Parts: {parts}") # Format: ISO, Parts: ('2024', '01', '15')

info

Walrus with regex is especially powerful in list comprehensions — you can match, extract, and filter in a single pass without temporary variables or nested if-blocks.
Performance Implications
performance.py
Python
1import timeit
2
3# Walrus avoids redundant function calls
4def expensive():
5 # Simulate expensive computation
6 return sum(range(1_000_000))
7
8# Without walrus — calls expensive() twice when condition is True
9def without_walrus():
10 if expensive() > 0:
11 return expensive() * 2
12 return 0
13
14# With walrus — calls expensive() once
15def with_walrus():
16 if (result := expensive()) > 0:
17 return result * 2
18 return 0
19
20# Benchmark
21t1 = timeit.timeit(without_walrus, number=100)
22t2 = timeit.timeit(with_walrus, number=100)
23print(f"Without walrus: {t1:.3f}s")
24print(f"With walrus: {t2:.3f}s")
25print(f"Speedup: {t1 / t2:.1f}x")
26
27# Real-world example: dictionary lookup with fallback
28cache = {}
29
30def get_or_compute(key):
31 # Without walrus:
32 if key in cache:
33 value = cache[key]
34 else:
35 value = expensive_computation(key)
36 cache[key] = value
37 return value
38
39 # With walrus:
40 # return cache[key] if key in cache else (cache.setdefault(key, expensive_computation(key)))
41
42# Avoid repeated len() calls
43items = list(range(1_000_000))
44
45def process_without():
46 results = []
47 for i in range(len(items)): # len called every iteration
48 if i < len(items) // 2:
49 results.append(items[i])
50 return results
51
52def process_with():
53 results = []
54 n = len(items)
55 for i in range(n): # len called once
56 if i < n // 2:
57 results.append(items[i])
58 return results

best practice

The walrus operator's main performance benefit is avoiding redundant function calls. If your function is cheap (like len()), the readability improvement is more important than any micro-optimization.
When Not to Use Walrus
anti_patterns.py
Python
1# Anti-pattern: Walrus makes code less readable
2# BAD — nested walrus in complex expression
3if (a := (b := compute()) > 0) and (c := process(b)):
4 result = a + c
5
6# GOOD — separate statements are clearer
7b = compute()
8if b > 0:
9 a = b > 0
10 c = process(b)
11 result = a + c
12
13# Anti-pattern: Using walrus when assignment is obvious
14# BAD — unnecessary walrus
15x = (y := 10) # just use: x = y = 10
16
17# BAD — walrus adds nothing
18for i in (n := range(10)):
19 pass # n serves no purpose
20
21# Anti-pattern: Side effects in conditions
22# BAD — side effect hidden in condition
23if (result := api_call()).status == 200:
24 process(result)
25
26# GOOD — explicit is better
27result = api_call()
28if result.status == 200:
29 process(result)
30
31# Anti-pattern: Multiple walrus in one expression
32# BAD — too many assignments in one line
33if (a := f()) and (b := g(a)) and (c := h(b)):
34 pass
35
36# GOOD — step by step
37a = f()
38if a:
39 b = g(a)
40 if b:
41 c = h(b)
42
43# Good use cases summary:
44# ✓ while loops reading input
45# ✓ regex matching + filtering
46# ✓ avoiding redundant function calls
47# ✓ list comprehension with expensive checks
48# ✗ simple assignments (use = instead)
49# ✗ complex nested expressions
50# ✗ side effects in conditions
$Blueprint — Engineering Documentation·Section ID: PYTHON-WALRUS·Revision: 1.0