When validating input or processing data, you often need to compute a value, check a condition on it, and then use that value. Without the walrus operator, you either repeat the computation or clutter your code with temporary variables. The := operator solves this by combining assignment and expression in one step.

The walrus operator (:=) allows assignment within expressions, introduced in Python 3.8. It assigns values to variables as part of a larger expression, reducing code repetition.

In If Statements

data
walrus_if_statements.py
Replay: real traced execution (multi-file project)
"""Walrus operator in if statements"""

# Basic walrus in if
print("Basic walrus in if:")

# Without walrus
data = [1, 2, 3, 4, 5]
length = len(data)
if length > 3:
    print(f"Large list: {length} items")

# With walrus - assign and check in one line
if (n := len(data)) > 3:
    print(f"Large list (walrus): {n} items")

# Avoid repeated calls
print("\nAvoid repeated calls:")

def expensive_computation():
    print("  Computing...")
    return 42

# Without walrus - calls function twice
if expensive_computation() > 40:
    result = expensive_computation()
    print(f"Result: {result}")

# With walrus - calls function once
if (result := expensive_computation()) > 40:
    print(f"Result (walrus): {result}")

# String processing
print("\nString processing:")

text = "Hello World"

# Check length and use it
if (length := len(text)) > 5:
    print(f"Long text ({length} chars): {text}")

# Check if text and get first word
if (first_word := text.split()[0] if text else None):
    print(f"First word: {first_word}")

# Input validation
print("\nInput validation:")

def get_username():
    return "alice"

# Validate and use input
if (username := get_username()) and len(username) >= 3:
    print(f"Valid username: {username}")
else:
    print("Invalid username")

# Chained conditions
print("\nChained conditions:")

data = {"score": 85, "grade": "B"}

# Check and extract value
if (score := data.get("score")) and score >= 80:
    print(f"Good score: {score}")

if (grade := data.get("grade")) and grade in ["A", "B"]:
    print(f"Passing grade: {grade}")

# Pattern matching with walrus
print("\nPattern matching with walrus:")

def parse_command(cmd):
    parts = cmd.split()
    return parts[0] if parts else None

command = "git commit -m 'message'"

if (cmd := parse_command(command)) == "git":
    print(f"Git command detected: {command}")

# Nested conditions
print("\nNested conditions:")

user = {"name": "Alice", "profile": {"age": 30}}

# Extract nested value
if (profile := user.get("profile")) and (age := profile.get("age")) >= 18:
    print(f"Adult user: {user['name']}, age {age}")

# Range checking
print("\nRange checking:")

numbers = [5, 2, 8, 1, 9, 3, 7]

# Check and use max value
if (max_val := max(numbers)) > 5:
    print(f"Max value {max_val} exceeds threshold")

# Check and use min value
if (min_val := min(numbers)) < 3:
    print(f"Min value {min_val} below threshold")

# File checking
print("\nFile checking:")

def read_config():
    return {"debug": True, "port": 8080}

# Check config and extract value
if (config := read_config()) and config.get("debug"):
    print(f"Debug mode enabled (port: {config.get('port')})")

# Practical example
print("\nPractical example:")

# Validate user input
def validate_email(email):
    return "@" in email and "." in email

email = "alice@example.com"
if (is_valid := validate_email(email)):
    print(f"Email '{email}' is valid")
    # Use is_valid later if needed

# Check and process result
def find_user(user_id):
    users = {1: "Alice", 2: "Bob"}
    return users.get(user_id)

if (user := find_user(1)):
    print(f"Found user: {user}")
else:
    print("User not found")

# Data processing pipeline
text = "  Hello World  "
if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned:
    print(f"Cleaned and checked: '{cleaned}' -> '{upper}'")

"""Walrus operator in if statements"""

# Basic walrus in if
print("Basic walrus in if:")

# Without walrus
data = [1, 2]
length = len(data)
if length > 3:
    print(f"Large list: {length} items")

# With walrus - assign and check in one line
if (n := len(data)) > 3:
    print(f"Large list (walrus): {n} items")

# Avoid repeated calls
print("\nAvoid repeated calls:")

def expensive_computation():
    print("  Computing...")
    return 42

# Without walrus - calls function twice
if expensive_computation() > 40:
    result = expensive_computation()
    print(f"Result: {result}")

# With walrus - calls function once
if (result := expensive_computation()) > 40:
    print(f"Result (walrus): {result}")

# String processing
print("\nString processing:")

text = "Hello World"

# Check length and use it
if (length := len(text)) > 5:
    print(f"Long text ({length} chars): {text}")

# Check if text and get first word
if (first_word := text.split()[0] if text else None):
    print(f"First word: {first_word}")

# Input validation
print("\nInput validation:")

def get_username():
    return "alice"

# Validate and use input
if (username := get_username()) and len(username) >= 3:
    print(f"Valid username: {username}")
else:
    print("Invalid username")

# Chained conditions
print("\nChained conditions:")

data = {"score": 85, "grade": "B"}

# Check and extract value
if (score := data.get("score")) and score >= 80:
    print(f"Good score: {score}")

if (grade := data.get("grade")) and grade in ["A", "B"]:
    print(f"Passing grade: {grade}")

# Pattern matching with walrus
print("\nPattern matching with walrus:")

def parse_command(cmd):
    parts = cmd.split()
    return parts[0] if parts else None

command = "git commit -m 'message'"

if (cmd := parse_command(command)) == "git":
    print(f"Git command detected: {command}")

# Nested conditions
print("\nNested conditions:")

user = {"name": "Alice", "profile": {"age": 30}}

# Extract nested value
if (profile := user.get("profile")) and (age := profile.get("age")) >= 18:
    print(f"Adult user: {user['name']}, age {age}")

# Range checking
print("\nRange checking:")

numbers = [5, 2, 8, 1, 9, 3, 7]

# Check and use max value
if (max_val := max(numbers)) > 5:
    print(f"Max value {max_val} exceeds threshold")

# Check and use min value
if (min_val := min(numbers)) < 3:
    print(f"Min value {min_val} below threshold")

# File checking
print("\nFile checking:")

def read_config():
    return {"debug": True, "port": 8080}

# Check config and extract value
if (config := read_config()) and config.get("debug"):
    print(f"Debug mode enabled (port: {config.get('port')})")

# Practical example
print("\nPractical example:")

# Validate user input
def validate_email(email):
    return "@" in email and "." in email

email = "alice@example.com"
if (is_valid := validate_email(email)):
    print(f"Email '{email}' is valid")
    # Use is_valid later if needed

# Check and process result
def find_user(user_id):
    users = {1: "Alice", 2: "Bob"}
    return users.get(user_id)

if (user := find_user(1)):
    print(f"Found user: {user}")
else:
    print("User not found")

# Data processing pipeline
text = "  Hello World  "
if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned:
    print(f"Cleaned and checked: '{cleaned}' -> '{upper}'")

"""Walrus operator in if statements"""

# Basic walrus in if
print("Basic walrus in if:")

# Without walrus
data = [1, 2, 3, 4, 5, 6]
length = len(data)
if length > 3:
    print(f"Large list: {length} items")

# With walrus - assign and check in one line
if (n := len(data)) > 3:
    print(f"Large list (walrus): {n} items")

# Avoid repeated calls
print("\nAvoid repeated calls:")

def expensive_computation():
    print("  Computing...")
    return 42

# Without walrus - calls function twice
if expensive_computation() > 40:
    result = expensive_computation()
    print(f"Result: {result}")

# With walrus - calls function once
if (result := expensive_computation()) > 40:
    print(f"Result (walrus): {result}")

# String processing
print("\nString processing:")

text = "Hello World"

# Check length and use it
if (length := len(text)) > 5:
    print(f"Long text ({length} chars): {text}")

# Check if text and get first word
if (first_word := text.split()[0] if text else None):
    print(f"First word: {first_word}")

# Input validation
print("\nInput validation:")

def get_username():
    return "alice"

# Validate and use input
if (username := get_username()) and len(username) >= 3:
    print(f"Valid username: {username}")
else:
    print("Invalid username")

# Chained conditions
print("\nChained conditions:")

data = {"score": 85, "grade": "B"}

# Check and extract value
if (score := data.get("score")) and score >= 80:
    print(f"Good score: {score}")

if (grade := data.get("grade")) and grade in ["A", "B"]:
    print(f"Passing grade: {grade}")

# Pattern matching with walrus
print("\nPattern matching with walrus:")

def parse_command(cmd):
    parts = cmd.split()
    return parts[0] if parts else None

command = "git commit -m 'message'"

if (cmd := parse_command(command)) == "git":
    print(f"Git command detected: {command}")

# Nested conditions
print("\nNested conditions:")

user = {"name": "Alice", "profile": {"age": 30}}

# Extract nested value
if (profile := user.get("profile")) and (age := profile.get("age")) >= 18:
    print(f"Adult user: {user['name']}, age {age}")

# Range checking
print("\nRange checking:")

numbers = [5, 2, 8, 1, 9, 3, 7]

# Check and use max value
if (max_val := max(numbers)) > 5:
    print(f"Max value {max_val} exceeds threshold")

# Check and use min value
if (min_val := min(numbers)) < 3:
    print(f"Min value {min_val} below threshold")

# File checking
print("\nFile checking:")

def read_config():
    return {"debug": True, "port": 8080}

# Check config and extract value
if (config := read_config()) and config.get("debug"):
    print(f"Debug mode enabled (port: {config.get('port')})")

# Practical example
print("\nPractical example:")

# Validate user input
def validate_email(email):
    return "@" in email and "." in email

email = "alice@example.com"
if (is_valid := validate_email(email)):
    print(f"Email '{email}' is valid")
    # Use is_valid later if needed

# Check and process result
def find_user(user_id):
    users = {1: "Alice", 2: "Bob"}
    return users.get(user_id)

if (user := find_user(1)):
    print(f"Found user: {user}")
else:
    print("User not found")

# Data processing pipeline
text = "  Hello World  "
if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned:
    print(f"Cleaned and checked: '{cleaned}' -> '{upper}'")

  1. data ← [1, 2, 3, 4, 5], length ← 5

    1"""Walrus operator in if statements"""23# Basic walrus in if4print("Basic walrus in if:")56# Without walrus7data→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]  #@data=[1, 2], [1, 2, 3, 4, 5, 6]8length→ 5 = len(data[1, 2, 3, 4, 5])9if length > 3:
    outputBasic walrus in if:
  2. if length > 3:

    8length = len(data)9if length5 > 3:10    print(f"Large list: {length5} items")
    outputLarge list: 5 items
  3. if (n := len(data)) > 3:

    12# With walrus - assign and check in one line13if (n5 := len(data[1, 2, 3, 4, 5])) > 3:14    print(f"Large list (walrus): {n5} items")
    outputLarge list (walrus): 5 items
  4. print(" Avoid repeated calls:")

    16# Avoid repeated calls17print("\nAvoid repeated calls:")
    output
    Avoid repeated calls:
  5. def expensive_computation():

    pass 1 of 3
    19def expensive_computation():20    print("  Computing...")21    return 42
    output  Computing...
    All 3 passes — pass 1 is the card above
    passresult
    1
    2
    342
  6. result ← 42

    24if expensive_computation() > 40:25    result→ 42 = expensive_computation()26    print(f"Result: {result42}")
    outputResult: 42
  7. if (result := expensive_computation()) > 40:

    28# With walrus - calls function once29if (result42 := expensive_computation()) > 40:30    print(f"Result (walrus): {result42}")
    outputResult (walrus): 42
  8. text ← Hello World

    32# String processing33print("\nString processing:")3435text→ Hello World = "Hello World"
    output
    String processing:
  9. if (length := len(text)) > 5:

    37# Check length and use it38if (length11 := len(textHello World)) > 5:39    print(f"Long text ({length11} chars): {textHello World}")
    outputLong text (11 chars): Hello World
  10. if (first_word := text.split()[0] if text else None):

    41# Check if text and get first word42if (first_wordHello := textHello World.split()[0] if text else None):43    print(f"First word: {first_wordHello}")
    outputFirst word: Hello
  11. print(" Input validation:")

    45# Input validation46print("\nInput validation:")
    output
    Input validation:
  12. if (username := get_username()) and len(username) >= 3:

    51# Validate and use input52if (usernamealice := get_username()) and len(username) >= 3:53    print(f"Valid username: {usernamealice}")54else:
    outputValid username: alice
  13. data ← {'score': 85, 'grade': 'B'}

    57# Chained conditions58print("\nChained conditions:")5960data→ {'score': 85, 'grade': 'B'} = {"score": 85, "grade": "B"}
    output
    Chained conditions:
  14. if (score := data.get("score")) and score >= 80:

    62# Check and extract value63if (score85 := data{'score': 85, 'grade': 'B'}.get("score")) and score >= 80:64    print(f"Good score: {score85}")
    outputGood score: 85
  15. if (grade := data.get("grade")) and grade in ["A", "B"]:

    66if (gradeB := data{'score': 85, 'grade': 'B'}.get("grade")) and grade in ["A", "B"]:67    print(f"Passing grade: {gradeB}")
    outputPassing grade: B
  16. command ← git commit -m 'message'

    69# Pattern matching with walrus70print("\nPattern matching with walrus:")7172def parse_command(cmd):73    parts = cmd.split()74    return parts[0] if parts else None7576command→ git commit -m 'message' = "git commit -m 'message'"
    output
    Pattern matching with walrus:
  17. parts ← ['git', 'commit', '-m', "'message'"]

    72def parse_command(cmdgit commit -m 'message'):73    parts→ ['git', 'commit', '-m', "'message'"] = cmdgit commit -m 'message'.split()74    return parts[0]git if parts['git', 'commit', '-m', "'message'"] else None
  18. if (cmd := parse_command(command)) == "git":

    78if (cmdgit := parse_command(commandgit commit -m 'message')) == "git":79    print(f"Git command detected: {commandgit commit -m 'message'}")
    outputGit command detected: git commit -m 'message'
  19. user ← {'name': 'Alice', 'profile': {'age': 30}}

    81# Nested conditions82print("\nNested conditions:")8384user→ {'name': 'Alice', 'profile': {'age': 30}} = {"name": "Alice", "profile": {"age": 30}}
    output
    Nested conditions:
  20. if (profile := user.get("profile")) and (age := profile.get("age")) >=…

    86# Extract nested value87if (profile{'age': 30} := user{'name': 'Alice', 'profile': {'age': 30}}.get("profile")) and (age30 := profile.get("age")) >= 18:88    print(f"Adult user: {user['name']Alice}, age {age30}")
    outputAdult user: Alice, age 30
  21. numbers ← [5, 2, 8, 1, 9, 3, 7]

    90# Range checking91print("\nRange checking:")9293numbers→ [5, 2, 8, 1, 9, 3, 7] = [5, 2, 8, 1, 9, 3, 7]
    output
    Range checking:
  22. if (max_val := max(numbers)) > 5:

    95# Check and use max value96if (max_val9 := max(numbers[5, 2, 8, 1, 9, 3, 7])) > 5:97    print(f"Max value {max_val9} exceeds threshold")
    outputMax value 9 exceeds threshold
  23. if (min_val := min(numbers)) < 3:

    99# Check and use min value100if (min_val1 := min(numbers[5, 2, 8, 1, 9, 3, 7])) < 3:101    print(f"Min value {min_val1} below threshold")
    outputMin value 1 below threshold
  24. print(" File checking:")

    103# File checking104print("\nFile checking:")
    output
    File checking:
  25. if (config := read_config()) and config.get("debug"):

    109# Check config and extract value110if (config{'debug': True, 'port': 8080} := read_config()) and config.get("debug"):111    print(f"Debug mode enabled (port: {config{'debug': True, 'port': 8080}.get('port')})")
    outputDebug mode enabled (port: 8080)
  26. email ← alice@example.com

    113# Practical example114print("\nPractical example:")115116# Validate user input117def validate_email(email):118    return "@" in email and "." in email119120email→ alice@example.com = "alice@example.com"121if (is_valid := validate_email(email)):
    output
    Practical example:
  27. def validate_email(email):

    116# Validate user input117def validate_email(emailalice@example.com):118    return "@" in emailalice@example.com and "." in email
  28. if (is_valid := validate_email(email)):

    120email = "alice@example.com"121if (is_validTrue := validate_email(emailalice@example.com)):122    print(f"Email '{emailalice@example.com}' is valid")123    # Use is_valid later if needed
    outputEmail 'alice@example.com' is valid
  29. users ← {1: 'Alice', 2: 'Bob'}

    125# Check and process result126def find_user(user_id1):127    users→ {1: 'Alice', 2: 'Bob'} = {1: "Alice", 2: "Bob"}128    return users{1: 'Alice', 2: 'Bob'}.get(user_id1)
  30. if (user := find_user(1)):

    130if (userAlice := find_user(1)):131    print(f"Found user: {userAlice}")132else:
    outputFound user: Alice
  31. text ← Hello World

    135# Data processing pipeline136text→   Hello World   = "  Hello World  "137if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned:
  32. if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned…

    136text = "  Hello World  "137if (cleanedHello World := text  Hello World  .strip()) and (upperHELLO WORLD := cleaned.upper()) != cleaned:138    print(f"Cleaned and checked: '{cleanedHello World}' -> '{upperHELLO WORLD}'")
    outputCleaned and checked: 'Hello World' -> 'HELLO WORLD'
  1. data ← [1, 2], length ← 2

    1"""Walrus operator in if statements"""23# Basic walrus in if4print("Basic walrus in if:")56# Without walrus7data→ [1, 2] = [1, 2]8length→ 2 = len(data[1, 2])9if length > 3:10    print(f"Large list: {length} items")1112# With walrus - assign and check in one line13if (n := len(data)) > 3:14    print(f"Large list (walrus): {n} items")1516# Avoid repeated calls17print("\nAvoid repeated calls:")
    outputBasic walrus in if:
    
    Avoid repeated calls:
  2. def expensive_computation():

    pass 1 of 3
    19def expensive_computation():20    print("  Computing...")21    return 42
    output  Computing...
    All 3 passes — pass 1 is the card above
    passresult
    1
    2
    342
  3. result ← 42

    24if expensive_computation() > 40:25    result→ 42 = expensive_computation()26    print(f"Result: {result42}")
    outputResult: 42
  4. if (result := expensive_computation()) > 40:

    28# With walrus - calls function once29if (result42 := expensive_computation()) > 40:30    print(f"Result (walrus): {result42}")
    outputResult (walrus): 42
  5. text ← Hello World

    32# String processing33print("\nString processing:")3435text→ Hello World = "Hello World"
    output
    String processing:
  6. if (length := len(text)) > 5:

    37# Check length and use it38if (length11 := len(textHello World)) > 5:39    print(f"Long text ({length11} chars): {textHello World}")
    outputLong text (11 chars): Hello World
  7. if (first_word := text.split()[0] if text else None):

    41# Check if text and get first word42if (first_wordHello := textHello World.split()[0] if text else None):43    print(f"First word: {first_wordHello}")
    outputFirst word: Hello
  8. print(" Input validation:")

    45# Input validation46print("\nInput validation:")
    output
    Input validation:
  9. if (username := get_username()) and len(username) >= 3:

    51# Validate and use input52if (usernamealice := get_username()) and len(username) >= 3:53    print(f"Valid username: {usernamealice}")54else:
    outputValid username: alice
  10. data ← {'score': 85, 'grade': 'B'}

    57# Chained conditions58print("\nChained conditions:")5960data→ {'score': 85, 'grade': 'B'} = {"score": 85, "grade": "B"}
    output
    Chained conditions:
  11. if (score := data.get("score")) and score >= 80:

    62# Check and extract value63if (score85 := data{'score': 85, 'grade': 'B'}.get("score")) and score >= 80:64    print(f"Good score: {score85}")
    outputGood score: 85
  12. if (grade := data.get("grade")) and grade in ["A", "B"]:

    66if (gradeB := data{'score': 85, 'grade': 'B'}.get("grade")) and grade in ["A", "B"]:67    print(f"Passing grade: {gradeB}")
    outputPassing grade: B
  13. command ← git commit -m 'message'

    69# Pattern matching with walrus70print("\nPattern matching with walrus:")7172def parse_command(cmd):73    parts = cmd.split()74    return parts[0] if parts else None7576command→ git commit -m 'message' = "git commit -m 'message'"
    output
    Pattern matching with walrus:
  14. parts ← ['git', 'commit', '-m', "'message'"]

    72def parse_command(cmdgit commit -m 'message'):73    parts→ ['git', 'commit', '-m', "'message'"] = cmdgit commit -m 'message'.split()74    return parts[0]git if parts['git', 'commit', '-m', "'message'"] else None
  15. if (cmd := parse_command(command)) == "git":

    78if (cmdgit := parse_command(commandgit commit -m 'message')) == "git":79    print(f"Git command detected: {commandgit commit -m 'message'}")
    outputGit command detected: git commit -m 'message'
  16. user ← {'name': 'Alice', 'profile': {'age': 30}}

    81# Nested conditions82print("\nNested conditions:")8384user→ {'name': 'Alice', 'profile': {'age': 30}} = {"name": "Alice", "profile": {"age": 30}}
    output
    Nested conditions:
  17. if (profile := user.get("profile")) and (age := profile.get("age")) >=…

    86# Extract nested value87if (profile{'age': 30} := user{'name': 'Alice', 'profile': {'age': 30}}.get("profile")) and (age30 := profile.get("age")) >= 18:88    print(f"Adult user: {user['name']Alice}, age {age30}")
    outputAdult user: Alice, age 30
  18. numbers ← [5, 2, 8, 1, 9, 3, 7]

    90# Range checking91print("\nRange checking:")9293numbers→ [5, 2, 8, 1, 9, 3, 7] = [5, 2, 8, 1, 9, 3, 7]
    output
    Range checking:
  19. if (max_val := max(numbers)) > 5:

    95# Check and use max value96if (max_val9 := max(numbers[5, 2, 8, 1, 9, 3, 7])) > 5:97    print(f"Max value {max_val9} exceeds threshold")
    outputMax value 9 exceeds threshold
  20. if (min_val := min(numbers)) < 3:

    99# Check and use min value100if (min_val1 := min(numbers[5, 2, 8, 1, 9, 3, 7])) < 3:101    print(f"Min value {min_val1} below threshold")
    outputMin value 1 below threshold
  21. print(" File checking:")

    103# File checking104print("\nFile checking:")
    output
    File checking:
  22. if (config := read_config()) and config.get("debug"):

    109# Check config and extract value110if (config{'debug': True, 'port': 8080} := read_config()) and config.get("debug"):111    print(f"Debug mode enabled (port: {config{'debug': True, 'port': 8080}.get('port')})")
    outputDebug mode enabled (port: 8080)
  23. email ← alice@example.com

    113# Practical example114print("\nPractical example:")115116# Validate user input117def validate_email(email):118    return "@" in email and "." in email119120email→ alice@example.com = "alice@example.com"121if (is_valid := validate_email(email)):
    output
    Practical example:
  24. def validate_email(email):

    116# Validate user input117def validate_email(emailalice@example.com):118    return "@" in emailalice@example.com and "." in email
  25. if (is_valid := validate_email(email)):

    120email = "alice@example.com"121if (is_validTrue := validate_email(emailalice@example.com)):122    print(f"Email '{emailalice@example.com}' is valid")123    # Use is_valid later if needed
    outputEmail 'alice@example.com' is valid
  26. users ← {1: 'Alice', 2: 'Bob'}

    125# Check and process result126def find_user(user_id1):127    users→ {1: 'Alice', 2: 'Bob'} = {1: "Alice", 2: "Bob"}128    return users{1: 'Alice', 2: 'Bob'}.get(user_id1)
  27. if (user := find_user(1)):

    130if (userAlice := find_user(1)):131    print(f"Found user: {userAlice}")132else:
    outputFound user: Alice
  28. text ← Hello World

    135# Data processing pipeline136text→   Hello World   = "  Hello World  "137if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned:
  29. if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned…

    136text = "  Hello World  "137if (cleanedHello World := text  Hello World  .strip()) and (upperHELLO WORLD := cleaned.upper()) != cleaned:138    print(f"Cleaned and checked: '{cleanedHello World}' -> '{upperHELLO WORLD}'")
    outputCleaned and checked: 'Hello World' -> 'HELLO WORLD'
  1. data ← [1, 2, 3, 4, 5, 6], length ← 6

    1"""Walrus operator in if statements"""23# Basic walrus in if4print("Basic walrus in if:")56# Without walrus7data→ [1, 2, 3, 4, 5, 6] = [1, 2, 3, 4, 5, 6]8length→ 6 = len(data[1, 2, 3, 4, 5, 6])9if length > 3:
    outputBasic walrus in if:
  2. if length > 3:

    8length = len(data)9if length6 > 3:10    print(f"Large list: {length6} items")
    outputLarge list: 6 items
  3. if (n := len(data)) > 3:

    12# With walrus - assign and check in one line13if (n6 := len(data[1, 2, 3, 4, 5, 6])) > 3:14    print(f"Large list (walrus): {n6} items")
    outputLarge list (walrus): 6 items
  4. print(" Avoid repeated calls:")

    16# Avoid repeated calls17print("\nAvoid repeated calls:")
    output
    Avoid repeated calls:
  5. def expensive_computation():

    pass 1 of 3
    19def expensive_computation():20    print("  Computing...")21    return 42
    output  Computing...
    All 3 passes — pass 1 is the card above
    passresult
    1
    2
    342
  6. result ← 42

    24if expensive_computation() > 40:25    result→ 42 = expensive_computation()26    print(f"Result: {result42}")
    outputResult: 42
  7. if (result := expensive_computation()) > 40:

    28# With walrus - calls function once29if (result42 := expensive_computation()) > 40:30    print(f"Result (walrus): {result42}")
    outputResult (walrus): 42
  8. text ← Hello World

    32# String processing33print("\nString processing:")3435text→ Hello World = "Hello World"
    output
    String processing:
  9. if (length := len(text)) > 5:

    37# Check length and use it38if (length11 := len(textHello World)) > 5:39    print(f"Long text ({length11} chars): {textHello World}")
    outputLong text (11 chars): Hello World
  10. if (first_word := text.split()[0] if text else None):

    41# Check if text and get first word42if (first_wordHello := textHello World.split()[0] if text else None):43    print(f"First word: {first_wordHello}")
    outputFirst word: Hello
  11. print(" Input validation:")

    45# Input validation46print("\nInput validation:")
    output
    Input validation:
  12. if (username := get_username()) and len(username) >= 3:

    51# Validate and use input52if (usernamealice := get_username()) and len(username) >= 3:53    print(f"Valid username: {usernamealice}")54else:
    outputValid username: alice
  13. data ← {'score': 85, 'grade': 'B'}

    57# Chained conditions58print("\nChained conditions:")5960data→ {'score': 85, 'grade': 'B'} = {"score": 85, "grade": "B"}
    output
    Chained conditions:
  14. if (score := data.get("score")) and score >= 80:

    62# Check and extract value63if (score85 := data{'score': 85, 'grade': 'B'}.get("score")) and score >= 80:64    print(f"Good score: {score85}")
    outputGood score: 85
  15. if (grade := data.get("grade")) and grade in ["A", "B"]:

    66if (gradeB := data{'score': 85, 'grade': 'B'}.get("grade")) and grade in ["A", "B"]:67    print(f"Passing grade: {gradeB}")
    outputPassing grade: B
  16. command ← git commit -m 'message'

    69# Pattern matching with walrus70print("\nPattern matching with walrus:")7172def parse_command(cmd):73    parts = cmd.split()74    return parts[0] if parts else None7576command→ git commit -m 'message' = "git commit -m 'message'"
    output
    Pattern matching with walrus:
  17. parts ← ['git', 'commit', '-m', "'message'"]

    72def parse_command(cmdgit commit -m 'message'):73    parts→ ['git', 'commit', '-m', "'message'"] = cmdgit commit -m 'message'.split()74    return parts[0]git if parts['git', 'commit', '-m', "'message'"] else None
  18. if (cmd := parse_command(command)) == "git":

    78if (cmdgit := parse_command(commandgit commit -m 'message')) == "git":79    print(f"Git command detected: {commandgit commit -m 'message'}")
    outputGit command detected: git commit -m 'message'
  19. user ← {'name': 'Alice', 'profile': {'age': 30}}

    81# Nested conditions82print("\nNested conditions:")8384user→ {'name': 'Alice', 'profile': {'age': 30}} = {"name": "Alice", "profile": {"age": 30}}
    output
    Nested conditions:
  20. if (profile := user.get("profile")) and (age := profile.get("age")) >=…

    86# Extract nested value87if (profile{'age': 30} := user{'name': 'Alice', 'profile': {'age': 30}}.get("profile")) and (age30 := profile.get("age")) >= 18:88    print(f"Adult user: {user['name']Alice}, age {age30}")
    outputAdult user: Alice, age 30
  21. numbers ← [5, 2, 8, 1, 9, 3, 7]

    90# Range checking91print("\nRange checking:")9293numbers→ [5, 2, 8, 1, 9, 3, 7] = [5, 2, 8, 1, 9, 3, 7]
    output
    Range checking:
  22. if (max_val := max(numbers)) > 5:

    95# Check and use max value96if (max_val9 := max(numbers[5, 2, 8, 1, 9, 3, 7])) > 5:97    print(f"Max value {max_val9} exceeds threshold")
    outputMax value 9 exceeds threshold
  23. if (min_val := min(numbers)) < 3:

    99# Check and use min value100if (min_val1 := min(numbers[5, 2, 8, 1, 9, 3, 7])) < 3:101    print(f"Min value {min_val1} below threshold")
    outputMin value 1 below threshold
  24. print(" File checking:")

    103# File checking104print("\nFile checking:")
    output
    File checking:
  25. if (config := read_config()) and config.get("debug"):

    109# Check config and extract value110if (config{'debug': True, 'port': 8080} := read_config()) and config.get("debug"):111    print(f"Debug mode enabled (port: {config{'debug': True, 'port': 8080}.get('port')})")
    outputDebug mode enabled (port: 8080)
  26. email ← alice@example.com

    113# Practical example114print("\nPractical example:")115116# Validate user input117def validate_email(email):118    return "@" in email and "." in email119120email→ alice@example.com = "alice@example.com"121if (is_valid := validate_email(email)):
    output
    Practical example:
  27. def validate_email(email):

    116# Validate user input117def validate_email(emailalice@example.com):118    return "@" in emailalice@example.com and "." in email
  28. if (is_valid := validate_email(email)):

    120email = "alice@example.com"121if (is_validTrue := validate_email(emailalice@example.com)):122    print(f"Email '{emailalice@example.com}' is valid")123    # Use is_valid later if needed
    outputEmail 'alice@example.com' is valid
  29. users ← {1: 'Alice', 2: 'Bob'}

    125# Check and process result126def find_user(user_id1):127    users→ {1: 'Alice', 2: 'Bob'} = {1: "Alice", 2: "Bob"}128    return users{1: 'Alice', 2: 'Bob'}.get(user_id1)
  30. if (user := find_user(1)):

    130if (userAlice := find_user(1)):131    print(f"Found user: {userAlice}")132else:
    outputFound user: Alice
  31. text ← Hello World

    135# Data processing pipeline136text→   Hello World   = "  Hello World  "137if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned:
  32. if (cleaned := text.strip()) and (upper := cleaned.upper()) != cleaned…

    136text = "  Hello World  "137if (cleanedHello World := text  Hello World  .strip()) and (upperHELLO WORLD := cleaned.upper()) != cleaned:138    print(f"Cleaned and checked: '{cleanedHello World}' -> '{upperHELLO WORLD}'")
    outputCleaned and checked: 'Hello World' -> 'HELLO WORLD'

The walrus operator shines when you need to capture a value while testing it. Parentheses are usually required around the assignment.

assignment expression Using `:=` to assign a value and use it in the same expression, eliminating redundant computations or awkward pre-assignment.

In While Loops

walrus_while_loops.py
Replay: real traced execution (multi-file project)
"""Walrus operator in while loops"""

# Basic while with walrus
print("Basic while with walrus:")

# Without walrus
data = [1, 2, 3, 4, 5]
index = 0
while index < len(data):
    item = data[index]
    print(f"  Item: {item}")
    index += 1

# With walrus - cleaner iteration pattern
print("\nWith walrus:")
items = iter([10, 20, 30, 40, 50])
while (item := next(items, None)) is not None:
    print(f"  Item: {item}")

# Reading lines
print("\nReading lines:")

# Simulate file reading
lines = iter(["Line 1", "Line 2", "Line 3", ""])

while (line := next(lines, None)) is not None and line != "":
    print(f"  Processing: {line}")

# Input loop
print("\nInput loop:")

# Simulate user input
inputs = iter(["hello", "world", "quit"])

def get_input():
    return next(inputs, None)

while (user_input := get_input()) != "quit":
    if user_input:
        print(f"  You entered: {user_input}")

# Chunk processing
print("\nChunk processing:")

def read_chunk(data, chunk_size):
    """Generator that yields chunks"""
    for i in range(0, len(data), chunk_size):
        yield data[i:i + chunk_size]

data = list(range(1, 11))
chunks = read_chunk(data, 3)

while (chunk := next(chunks, None)) is not None:
    print(f"  Processing chunk: {chunk}")

# Accumulator pattern
print("\nAccumulator pattern:")

numbers = [5, 10, 15, 20, 25, 30]
index = 0
total = 0

while (index < len(numbers)) and ((current := numbers[index]) < 25):
    total += current
    print(f"  Added {current}, total: {total}")
    index += 1

# Queue processing
print("\nQueue processing:")

queue = [1, 2, 3, 4, 5]

while queue and (item := queue.pop(0)) < 4:
    print(f"  Processing: {item}")

print(f"Remaining: {queue}")

# Stream processing
print("\nStream processing:")

def generate_data():
    """Simulate data stream"""
    for i in range(1, 6):
        yield i * 10

stream = generate_data()

while (value := next(stream, None)) is not None:
    if value > 30:
        print(f"  Value {value} exceeds threshold")
    else:
        print(f"  Value {value} within range")

# Parse until delimiter
print("\nParse until delimiter:")

tokens = iter(["token1", "token2", "STOP", "token3", "token4"])

result = []
while (token := next(tokens, None)) and token != "STOP":
    result.append(token)

print(f"Tokens before STOP: {result}")

# Buffer reading
print("\nBuffer reading:")

buffer = [b'Hello', b' ', b'World', b'']

output = []
while (chunk := buffer.pop(0) if buffer else None):
    output.append(chunk)

print(f"Read: {b''.join(output).decode()}")

# Practical example
print("\nPractical example:")

# Process commands until exit
commands = iter(["print hello", "print world", "count 5", "exit"])

while (cmd := next(commands, None)) and not cmd.startswith("exit"):
    parts = cmd.split()
    action = parts[0]

    if action == "print":
        print(f"  Output: {' '.join(parts[1:])}")
    elif action == "count":
        count = int(parts[1])
        print(f"  Count: {count}")

# Process data with validation
data_stream = iter([{"value": 10}, {"value": 20}, {"value": -1}, {"value": 30}])

total = 0
while (item := next(data_stream, None)) and (val := item.get("value", -1)) >= 0:
    total += val
    print(f"  Added {val}, running total: {total}")

print(f"Final total: {total}")

# Read until condition
numbers = iter([1, 3, 5, 7, 9, 11, 13])
collected = []

while (n := next(numbers, None)) is not None and n < 10:
    collected.append(n)

print(f"Collected (< 10): {collected}")

  1. data ← [1, 2, 3, 4, 5], index ← 0

    1"""Walrus operator in while loops"""23# Basic while with walrus4print("Basic while with walrus:")56# Without walrus7data→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]8index→ 0 = 09while index < len(data):
    outputBasic while with walrus:
  2. item ← 1, index ← 1

    pass 1 of 5
    8index = 09while index0 < len(data[1, 2, 3, 4, 5]):10    item→ 1 = data[index]111    print(f"  Item: {item1}")12    index→ 1 += 1
    output  Item: 1
    All 5 passes — pass 1 is the card above
    passdata[index]itemindex
    1110 1
    2221 2
    3332 3
    4443 4
    5554 5
  3. items ← ⟨list_iterator A⟩

    14# With walrus - cleaner iteration pattern15print("\nWith walrus:")16items→ ⟨list_iterator A⟩ = iter([10, 20, 30, 40, 50])17while (item := next(items, None)) is not None:
    output
    With walrus:
  4. while (item := next(items, None)) is not None:

    pass 1 of 5
    16items = iter([10, 20, 30, 40, 50])17while (item10 := next(items⟨list_iterator A⟩, None)) is not None:18    print(f"  Item: {item10}")
    output  Item: 10
    All 5 passes — pass 1 is the card above
    passitem
    110
    220
    330
    440
    550
  5. lines ← ⟨list_iterator B⟩

    20# Reading lines21print("\nReading lines:")2223# Simulate file reading24lines→ ⟨list_iterator B⟩ = iter(["Line 1", "Line 2", "Line 3", ""])
    output
    Reading lines:
  6. while (line := next(lines, None)) is not None and line != "":

    pass 1 of 3
    26while (lineLine 1 := next(lines⟨list_iterator B⟩, None)) is not None and line != "":27    print(f"  Processing: {lineLine 1}")
    output  Processing: Line 1
    All 3 passes — pass 1 is the card above
    passline
    1Line 1
    2Line 2
    3Line 3
  7. inputs ← ⟨list_iterator C⟩

    29# Input loop30print("\nInput loop:")3132# Simulate user input33inputs→ ⟨list_iterator C⟩ = iter(["hello", "world", "quit"])
    output
    Input loop:
  8. def get_input():

    pass 1 of 3
    35def get_input():36    return next(inputs⟨list_iterator C⟩, None)
    All 3 passes — pass 1 is the card above
    passuser_input
    1hello
    2world
    3
  9. while (user_input := get_input()) != "quit":

    pass 1 of 2
    38while (user_inputhello := get_input()) != "quit":39    if user_input:40        print(f"  You entered: {user_input}")
  10. if user_input:

    pass 1 of 2
    38while (user_input := get_input()) != "quit":39    if user_inputhello:40        print(f"  You entered: {user_inputhello}")
    output  You entered: hello
  11. while (user_input := get_input()) != "quit":

    pass 2 of 2
    38while (user_inputworld := get_input()) != "quit":39    if user_input:40        print(f"  You entered: {user_input}")
  12. if user_input:

    pass 2 of 2
    38while (user_input := get_input()) != "quit":39    if user_inputworld:40        print(f"  You entered: {user_inputworld}")
    output  You entered: world
  13. data ← [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], chunks ← ⟨generator object read_chunk D⟩

    42# Chunk processing43print("\nChunk processing:")4445def read_chunk(data, chunk_size):46    """Generator that yields chunks"""47    for i in range(0, len(data), chunk_size):48        yield data[i:i + chunk_size]4950data→ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] = list(range(1, 11))51chunks→ ⟨generator object read_chunk D⟩ = read_chunk(data[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3)
    output
    Chunk processing:
  14. def read_chunk(data, chunk_size):

    45def read_chunk(data[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], chunk_size3):46    """Generator that yields chunks"""47    for i in range(0, len(data), chunk_size):
  15. for i in range(0, len(data), chunk_size):

    pass 1 of 4
    46"""Generator that yields chunks"""47for i0 in range(0, len(data[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), chunk_size3):48    yield data[i:i + chunk_size][1, 2, 3]
    All 4 passes — pass 1 is the card above
    passidata[i:i + chunk_size]
    10[1, 2, 3]
    23[4, 5, 6]
    36[7, 8, 9]
    49[10]
  16. while (chunk := next(chunks, None)) is not None:

    pass 1 of 4
    47    for i in range(0, len(data), chunk_size):48        yield data[i:i + chunk_size][1, 2, 3]4950data = list(range(1, 11))51chunks = read_chunk(data, 3)5253while (chunk[1, 2, 3] := next(chunks⟨generator object read_chunk D⟩, None)) is not None:54    print(f"  Processing chunk: {chunk[1, 2, 3]}")
    output  Processing chunk: [1, 2, 3]
    All 4 passes — pass 1 is the card above
    passchunkdata[i:i + chunk_size]
    1[1, 2, 3][1, 2, 3]
    2[4, 5, 6][4, 5, 6]
    3[7, 8, 9][7, 8, 9]
    4[10][10]
  17. numbers ← [5, 10, 15, 20, 25, 30], index ← 0, total ← 0

    56# Accumulator pattern57print("\nAccumulator pattern:")5859numbers→ [5, 10, 15, 20, 25, 30] = [5, 10, 15, 20, 25, 30]60index→ 0 = 061total→ 0 = 0
    output
    Accumulator pattern:
  18. total ← 5, index ← 1

    pass 1 of 4
    63while (index0 < len(numbers[5, 10, 15, 20, 25, 30])) and ((current5 := numbers[index]5) < 25):64    total→ 5 += current565    print(f"  Added {current5}, total: {total5}")66    index→ 1 += 1
    output  Added 5, total: 5
    All 4 passes — pass 1 is the card above
    passnumbers[index]currenttotalindex
    1550 50 1
    210105 151 2
    3151515 302 3
    4202030 503 4
  19. queue ← [1, 2, 3, 4, 5]

    68# Queue processing69print("\nQueue processing:")7071queue→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]
    output
    Queue processing:
  20. while queue and (item := queue.pop(0)) < 4:

    pass 1 of 3
    73while queue[2, 3, 4, 5] and (item1 := queue.pop(0)) < 4:74    print(f"  Processing: {item1}")
    output  Processing: 1
    All 3 passes — pass 1 is the card above
    passqueueitem
    1[2, 3, 4, 5]1
    2[3, 4, 5]2
    3[4, 5]3
  21. stream ← ⟨generator object generate_data E⟩

    76print(f"Remaining: {queue[5]}")7778# Stream processing79print("\nStream processing:")8081def generate_data():82    """Simulate data stream"""83    for i in range(1, 6):84        yield i * 108586stream→ ⟨generator object generate_data E⟩ = generate_data()
    outputRemaining: [5]
    
    Stream processing:
  22. for i in range(1, 6):

    pass 1 of 5
    82"""Simulate data stream"""83for i1 in range(1, 6):84    yield i1 * 10
    All 5 passes — pass 1 is the card above
    passivalue
    11
    22
    33
    4440
    5550
  23. while (value := next(stream, None)) is not None:

    pass 1 of 5
    88while (value10 := next(stream⟨generator object generate_data E⟩, None)) is not None:89    if value > 30:90        print(f"  Value {value} exceeds threshold")
    All 5 passes — pass 1 is the card above
    passvaluei
    110
    220
    330
    4404
    5505
  24. else:

    pass 1 of 3
    83    for i in range(1, 6):84        yield i1 * 108586stream = generate_data()8788while (value := next(stream, None)) is not None:89    if value > 30:90        print(f"  Value {value} exceeds threshold")91    else:92        print(f"  Value {value10} within range")
    output  Value 10 within range
    All 3 passes — pass 1 is the card above
    passvaluei
    1101
    2202
    3303
  25. if value > 30:

    pass 1 of 2
    83    for i in range(1, 6):84        yield i4 * 108586stream = generate_data()8788while (value := next(stream, None)) is not None:89    if value40 > 30:90        print(f"  Value {value40} exceeds threshold")91    else:
    output  Value 40 exceeds threshold
  26. if value > 30:

    pass 2 of 2
    83    for i in range(1, 6):84        yield i5 * 108586stream = generate_data()8788while (value := next(stream, None)) is not None:89    if value50 > 30:90        print(f"  Value {value50} exceeds threshold")91    else:
    output  Value 50 exceeds threshold
  27. tokens ← ⟨list_iterator F⟩, result ← []

    94# Parse until delimiter95print("\nParse until delimiter:")9697tokens→ ⟨list_iterator F⟩ = iter(["token1", "token2", "STOP", "token3", "token4"])9899result→ [] = []100while (token := next(tokens, None)) and token != "STOP":
    output
    Parse until delimiter:
  28. result ← ['token1']

    pass 1 of 2
    99result = []100while (tokentoken1 := next(tokens⟨list_iterator F⟩, None)) and token != "STOP":101    result→ ['token1'].append(tokentoken1)
  29. result ← ['token1', 'token2']

    pass 2 of 2
    99result = []100while (tokentoken2 := next(tokens⟨list_iterator F⟩, None)) and token != "STOP":101    result→ ['token1', 'token2'].append(tokentoken2)
  30. buffer ← [b'Hello', b' ', b'World', b''], output ← []

    103print(f"Tokens before STOP: {result['token1', 'token2']}")104105# Buffer reading106print("\nBuffer reading:")107108buffer→ [b'Hello', b' ', b'World', b''] = [b'Hello', b' ', b'World', b'']109110output→ [] = []111while (chunk := buffer.pop(0) if buffer else None):
    outputTokens before STOP: ['token1', 'token2']
    
    Buffer reading:
  31. output ← [b'Hello']

    pass 1 of 3
    110output = []111while (chunkb'Hello' := buffer[b' ', b'World', b''].pop(0) if buffer else None):112    output→ [b'Hello'].append(chunkb'Hello')
    All 3 passes — pass 1 is the card above
    passbufferchunkoutput
    1[b' ', b'World', b'']b'Hello'[] [b'Hello']
    2[b'World', b'']b' '[b'Hello'] [b'Hello', b' ']
    3[b'']b'World'[b'Hello', b' '] [b'Hello', b' ', b'World']
  32. commands ← ⟨list_iterator G⟩

    114print(f"Read: {b''.join(output[b'Hello', b' ', b'World']).decode()}")115116# Practical example117print("\nPractical example:")118119# Process commands until exit120commands→ ⟨list_iterator G⟩ = iter(["print hello", "print world", "count 5", "exit"])
    outputRead: Hello World
    
    Practical example:
  33. parts ← ['print', 'hello'], action ← print

    pass 1 of 3
    122while (cmdprint hello := next(commands⟨list_iterator G⟩, None)) and not cmd.startswith("exit"):123    parts→ ['print', 'hello'] = cmdprint hello.split()124    action→ print = parts[0]print
    All 3 passes — pass 1 is the card above
    passcmdparts[0]parts[1:]parts[1]partsactioncount
    1print helloprint['hello']['print', 'hello']print
    2print worldprint['world']['print', 'world']print
    3count 5count5['count', '5']count5
  34. if action == "print":

    pass 1 of 2
    126if actionprint == "print":127    print(f"  Output: {' '.join(parts[1:]['hello'])}")128elif action == "count":
    output  Output: hello
  35. if action == "print":

    pass 2 of 2
    126if actionprint == "print":127    print(f"  Output: {' '.join(parts[1:]['world'])}")128elif action == "count":
    output  Output: world
  36. count ← 5

    127    print(f"  Output: {' '.join(parts[1:])}")128elif actioncount == "count":129    count→ 5 = int(parts[1]5)130    print(f"  Count: {count5}")
    output  Count: 5
  37. data_stream ← ⟨list_iterator H⟩, total ← 0

    132# Process data with validation133data_stream→ ⟨list_iterator H⟩ = iter([{"value": 10}, {"value": 20}, {"value": -1}, {"value": 30}])134135total→ 0 = 0136while (item := next(data_stream, None)) and (val := item.get("value", -1)) >= 0:
  38. total ← 10

    pass 1 of 2
    135total = 0136while (item{'value': 10} := next(data_stream⟨list_iterator H⟩, None)) and (val10 := item.get("value", -1)) >= 0:137    total→ 10 += val10138    print(f"  Added {val10}, running total: {total10}")
    output  Added 10, running total: 10
  39. total ← 30

    pass 2 of 2
    135total = 0136while (item{'value': 20} := next(data_stream⟨list_iterator H⟩, None)) and (val20 := item.get("value", -1)) >= 0:137    total→ 30 += val20138    print(f"  Added {val20}, running total: {total30}")
    output  Added 20, running total: 30
  40. numbers ← ⟨list_iterator I⟩, collected ← []

    140print(f"Final total: {total30}")141142# Read until condition143numbers→ ⟨list_iterator I⟩ = iter([1, 3, 5, 7, 9, 11, 13])144collected→ [] = []
    outputFinal total: 30
  41. collected ← [1]

    pass 1 of 5
    146while (n1 := next(numbers⟨list_iterator I⟩, None)) is not None and n < 10:147    collected→ [1].append(n1)
    All 5 passes — pass 1 is the card above
    passncollected
    11[] [1]
    23[1] [1, 3]
    35[1, 3] [1, 3, 5]
    47[1, 3, 5] [1, 3, 5, 7]
    59[1, 3, 5, 7] [1, 3, 5, 7, 9]
  42. print(f"Collected (< 10): {collected}")

    149print(f"Collected (< 10): {collected[1, 3, 5, 7, 9]}")
    outputCollected (< 10): [1, 3, 5, 7, 9]

This pattern replaces the awkward "prime the loop" idiom where you read once before the loop and again inside it.

loop assignment Using `:=` in loop conditions to assign and test in one expression, creating cleaner read-until patterns.

In Comprehensions

walrus_comprehensions.py
Replay: real traced execution (multi-file project)
"""Walrus operator in comprehensions"""

# Basic list comprehension
print("Basic list comprehension:")

# Without walrus - compute twice
numbers = [1, 2, 3, 4, 5]
squared = [n * n for n in numbers if n * n > 10]
print(f"Squared (>10): {squared}")

# With walrus - compute once
squared_walrus = [sq for n in numbers if (sq := n * n) > 10]
print(f"Squared walrus: {squared_walrus}")

# Expensive computation
print("\nExpensive computation:")

def process(n):
    print(f"  Processing {n}")
    return n * 10

numbers = [1, 2, 3, 4, 5]

# Without walrus - processes each number twice
result = [process(n) for n in numbers if process(n) > 25]
print(f"Result (called twice): {result}")

# With walrus - processes once
result_walrus = [p for n in numbers if (p := process(n)) > 25]
print(f"Result walrus (called once): {result_walrus}")

# String processing
print("\nString processing:")

words = ["hello", "world", "python", "programming"]

# Get uppercase versions only for words longer than 5
result = [upper for word in words if (upper := word.upper()) and len(word) > 5]
print(f"Long words (uppercase): {result}")

# Data transformation
print("\nData transformation:")

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Square numbers and filter
squared_evens = [sq for n in data if (sq := n * n) % 2 == 0]
print(f"Even squares: {squared_evens}")

# Dict comprehension
print("\nDict comprehension:")

numbers = [1, 2, 3, 4, 5]

# Create dict with computed values
squares_dict = {n: sq for n in numbers if (sq := n * n) < 20}
print(f"Squares dict: {squares_dict}")

# Nested comprehension
print("\nNested comprehension:")

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# Flatten and filter with transformation
result = [doubled for row in matrix for item in row if (doubled := item * 2) > 8]
print(f"Filtered doubled: {result}")

# Generator expression
print("\nGenerator expression:")

numbers = range(1, 11)

# Generator with walrus
gen = (sq for n in numbers if (sq := n * n) > 20)
result = list(gen)
print(f"Squares > 20: {result}")

# Any/All with walrus
print("\nAny/All with walrus:")

data = [1, 2, 3, 4, 5]

# Check if any squared value > 20
if any((sq := n * n) > 20 for n in data):
    print(f"Found square > 20")

# Get first match with walrus
numbers = [1, 2, 3, 4, 5, 6, 7]
first_big = next((sq for n in numbers if (sq := n * n) > 20), None)
print(f"First square > 20: {first_big}")

# Set comprehension
print("\nSet comprehension:")

words = ["hello", "world", "hello", "python", "world"]

# Get unique lengths
lengths = {ln for word in words if (ln := len(word)) > 4}
print(f"Unique lengths > 4: {lengths}")

# Multiple conditions
print("\nMultiple conditions:")

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Multiple transformations
result = [
    doubled
    for n in numbers
    if (doubled := n * 2) > 5
    if (squared := doubled * doubled) < 200
]
print(f"Filtered transformations: {result}")

# Practical example
print("\nPractical example:")

# Process user data
users = [
    {"name": "Alice", "age": 30},
    {"name": "Bob", "age": 25},
    {"name": "Charlie", "age": 35}
]

# Get names of users over 26
names = [name for user in users if (age := user.get("age", 0)) > 26 and (name := user.get("name"))]
print(f"Users over 26: {names}")

# Parse and validate
raw_data = ["10", "20", "abc", "30", "def"]

def try_parse(s):
    try:
        return int(s)
    except ValueError:
        return None

# Get valid integers > 15
valid = [num for s in raw_data if (num := try_parse(s)) is not None and num > 15]
print(f"Valid numbers > 15: {valid}")

# File processing simulation
lines = ["# comment", "data: 10", "# ignore", "data: 20", "data: 30"]

# Extract data lines and parse
data_values = [
    int(parts[1])
    for line in lines
    if not line.startswith("#")
    if (parts := line.split(": "))
    if len(parts) == 2
]
print(f"Data values: {data_values}")

  1. numbers ← [1, 2, 3, 4, 5], squared ← [16, 25], sq ← 25, squared_walrus ← [16, 25]

    1"""Walrus operator in comprehensions"""23# Basic list comprehension4print("Basic list comprehension:")56# Without walrus - compute twice7numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]8squared→ [16, 25] = [n * n for n in numbers[1, 2, 3, 4, 5] if n * n > 10]9print(f"Squared (>10): {squared[16, 25]}")1011# With walrus - compute once12squared_walrus→ [16, 25] = [sq→ 25 for n in numbers[1, 2, 3, 4, 5] if (sq := n * n) > 10]13print(f"Squared walrus: {squared_walrus[16, 25]}")1415# Expensive computation16print("\nExpensive computation:")1718def process(n):19    print(f"  Processing {n}")20    return n * 102122numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]2324# Without walrus - processes each number twice25result = [process(n) for n in numbers[1, 2, 3, 4, 5] if process(n) > 25]26print(f"Result (called twice): {result}")
    outputBasic list comprehension:
    Squared (>10): [16, 25]
    Squared walrus: [16, 25]
    
    Expensive computation:
  2. def process(n):

    pass 1 of 13
    18def process(n1):19    print(f"  Processing {n1}")20    return n1 * 10
    output  Processing 1
    13 passes — pass 1 is the card above
    passn
    11
    22
    33
    43
    54
    64
    75
    85
    91
    ⋯ 2 more passes ⋯
    124
    135
  3. result ← [30, 40, 50]

    24# Without walrus - processes each number twice25result→ [30, 40, 50] = [process(n) for n in numbers[1, 2, 3, 4, 5] if process(n) > 25]26print(f"Result (called twice): {result[30, 40, 50]}")2728# With walrus - processes once29result_walrus = [p(empty) for n in numbers[1, 2, 3, 4, 5] if (p := process(n)) > 25]30print(f"Result walrus (called once): {result_walrus}")
    outputResult (called twice): [30, 40, 50]
  4. p ← 50, result_walrus ← [30, 40, 50], words ← ['hello', 'world', 'python', 'programming']

    28# With walrus - processes once29result_walrus→ [30, 40, 50] = [p→ 50 for n in numbers[1, 2, 3, 4, 5] if (p := process(n)) > 25]30print(f"Result walrus (called once): {result_walrus[30, 40, 50]}")3132# String processing33print("\nString processing:")3435words→ ['hello', 'world', 'python', 'programming'] = ["hello", "world", "python", "programming"]3637# Get uppercase versions only for words longer than 538result→ ['PYTHON', 'PROGRAMMING'] = [upper→ PROGRAMMING for word in words['hello', 'world', 'python', 'programming'] if (upper := word.upper()) and len(word) > 5]39print(f"Long words (uppercase): {result['PYTHON', 'PROGRAMMING']}")4041# Data transformation42print("\nData transformation:")4344data→ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]4546# Square numbers and filter47squared_evens→ [4, 16, 36, 64, 100] = [sq→ 100 for n in data[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] if (sq := n * n) % 2 == 0]48print(f"Even squares: {squared_evens[4, 16, 36, 64, 100]}")4950# Dict comprehension51print("\nDict comprehension:")5253numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]5455# Create dict with computed values56squares_dict→ {1: 1, 2: 4, 3: 9, 4: 16} = {n: sq→ 25 for n in numbers[1, 2, 3, 4, 5] if (sq := n * n) < 20}57print(f"Squares dict: {squares_dict{1: 1, 2: 4, 3: 9, 4: 16}}")5859# Nested comprehension60print("\nNested comprehension:")6162matrix→ [[1, 2, 3], [4, 5, 6], [7, 8, 9]] = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]6364# Flatten and filter with transformation65result→ [10, 12, 14, 16, 18] = [doubled→ 18 for row in matrix[[1, 2, 3], [4, 5, 6], [7, 8, 9]] for item in row if (doubled := item * 2) > 8]66print(f"Filtered doubled: {result[10, 12, 14, 16, 18]}")6768# Generator expression69print("\nGenerator expression:")7071numbers→ range(1, 11) = range(1, 11)7273# Generator with walrus74gen→ <generator object <genexpr> at ⟨addr A⟩> = (sq25 for n in numbersrange(1, 11) if (sq := n * n) > 20)75result→ [25, 36, 49, 64, 81, 100] = list(gen<generator object <genexpr> at ⟨addr A⟩>)76print(f"Squares > 20: {result[25, 36, 49, 64, 81, 100]}")7778# Any/All with walrus79print("\nAny/All with walrus:")8081data→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]
    outputResult walrus (called once): [30, 40, 50]
    
    String processing:
    Long words (uppercase): ['PYTHON', 'PROGRAMMING']
    
    Data transformation:
    Even squares: [4, 16, 36, 64, 100]
    
    Dict comprehension:
    Squares dict: {1: 1, 2: 4, 3: 9, 4: 16}
    
    Nested comprehension:
    Filtered doubled: [10, 12, 14, 16, 18]
    
    Generator expression:
    Squares > 20: [25, 36, 49, 64, 81, 100]
    
    Any/All with walrus:
  5. if any((sq := n * n) > 20 for n in data):

    83# Check if any squared value > 2084if any((sq25 := n * n) > 20 for n in data[1, 2, 3, 4, 5]):85    print(f"Found square > 20")
    outputFound square > 20
  6. numbers ← [1, 2, 3, 4, 5, 6, 7], first_big ← 25, words ← ['hello', 'world', 'hello', 'python', 'world']

    87# Get first match with walrus88numbers→ [1, 2, 3, 4, 5, 6, 7] = [1, 2, 3, 4, 5, 6, 7]89first_big→ 25 = next((sq25 for n in numbers[1, 2, 3, 4, 5, 6, 7] if (sq := n * n) > 20), None)90print(f"First square > 20: {first_big25}")9192# Set comprehension93print("\nSet comprehension:")9495words→ ['hello', 'world', 'hello', 'python', 'world'] = ["hello", "world", "hello", "python", "world"]9697# Get unique lengths98lengths→ {5, 6} = {ln→ 5 for word in words['hello', 'world', 'hello', 'python', 'world'] if (ln := len(word)) > 4}99print(f"Unique lengths > 4: {lengths{5, 6}}")100101# Multiple conditions102print("\nMultiple conditions:")103104numbers→ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]105106# Multiple transformations107result→ [6, 8, 10, 12, 14] = [108    doubled→ 20 109    for n in numbers[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 110    if (doubled→ 20 := n * 2) > 5 111    if (squared→ 400 := doubled→ 20 * doubled) < 200112]113print(f"Filtered transformations: {result[6, 8, 10, 12, 14]}")114115# Practical example116print("\nPractical example:")117118# Process user data119users→ [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 35}] = [120    {"name": "Alice", "age": 30},121    {"name": "Bob", "age": 25},122    {"name": "Charlie", "age": 35}123]124125# Get names of users over 26126names→ ['Alice', 'Charlie'] = [name→ Charlie for user in users[{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 35}] if (age→ 35 := user.get("age", 0)) > 26 and (name := user.get("name"))]127print(f"Users over 26: {names['Alice', 'Charlie']}")128129# Parse and validate130raw_data→ ['10', '20', 'abc', '30', 'def'] = ["10", "20", "abc", "30", "def"]131132def try_parse(s):133    try:134        return int(s)135    except ValueError:136        return None137138# Get valid integers > 15139valid = [num(empty) for s in raw_data['10', '20', 'abc', '30', 'def'] if (num := try_parse(s)) is not None and num > 15]140print(f"Valid numbers > 15: {valid}")
    outputFirst square > 20: 25
    
    Set comprehension:
    Unique lengths > 4: {5, 6}
    
    Multiple conditions:
    Filtered transformations: [6, 8, 10, 12, 14]
    
    Practical example:
    Users over 26: ['Alice', 'Charlie']
  7. def try_parse(s):

    pass 1 of 5
    132def try_parse(s10):133    try:134        return int(s)
    All 5 passes — pass 1 is the card above
    passs
    110
    220
    3abc
    430
    5def
  8. try:

    pass 1 of 5
    132def try_parse(s):133    try:134        return int(s10)135    except ValueError:
    All 5 passes — pass 1 is the card above
    passs
    110
    220
    3abc
    430
    5def
  9. num ← None, valid ← [20, 30], lines ← ['# comment', 'data: 10', '# ignore', 'data: 20', 'data: 30']

    138# Get valid integers > 15139valid→ [20, 30] = [num→ None for s in raw_data['10', '20', 'abc', '30', 'def'] if (num := try_parse(s)) is not None and num > 15]140print(f"Valid numbers > 15: {valid[20, 30]}")141142# File processing simulation143lines→ ['# comment', 'data: 10', '# ignore', 'data: 20', 'data: 30'] = ["# comment", "data: 10", "# ignore", "data: 20", "data: 30"]144145# Extract data lines and parse146data_values→ [10, 20, 30] = [147    int(parts[1]→ 30)148    for line in lines['# comment', 'data: 10', '# ignore', 'data: 20', 'data: 30']149    if not line.startswith("#")150    if (parts→ ['data', '30'] := line.split(": "))151    if len(parts→ ['data', '30']) == 2152]153print(f"Data values: {data_values[10, 20, 30]}")
    outputValid numbers > 15: [20, 30]
    Data values: [10, 20, 30]

This is particularly valuable when the computation is expensive or has side effects you want to minimize.

comprehension capture Using `:=` inside list/dict comprehensions to avoid computing expensive expressions twice in the filter and output.

Avoiding Repeated Calls

walrus_avoid_repeated_calls.py
Replay: real traced execution (multi-file project)
"""Walrus operator to avoid repeated calls"""

# Avoiding double computation
print("Avoiding double computation:")

def expensive_function(x):
    print(f"  Computing for {x}...")
    return x ** 3

# Without walrus - calls function twice
x = 5
if expensive_function(x) > 100:
    result = expensive_function(x)
    print(f"Result: {result}")

# With walrus - calls once
x = 5
if (result := expensive_function(x)) > 100:
    print(f"Result (walrus): {result}")

# Method calls
print("\nMethod calls:")

text = "  Hello World  "

# Without walrus - strip called twice
if len(text.strip()) > 5:
    cleaned = text.strip()
    print(f"Cleaned: '{cleaned}'")

# With walrus - strip called once
if len(cleaned := text.strip()) > 5:
    print(f"Cleaned (walrus): '{cleaned}'")

# Regex matching
print("\nRegex matching:")

import re

text = "Error: File not found"

# Without walrus - match called twice
pattern = r"Error: (.*)"
if re.match(pattern, text):
    match = re.match(pattern, text)
    print(f"Error message: {match.group(1)}")

# With walrus - match called once
if (match := re.match(pattern, text)):
    print(f"Error message (walrus): {match.group(1)}")

# Database query
print("\nDatabase query:")

def find_user(user_id):
    print(f"  Querying database for user {user_id}...")
    users = {1: {"name": "Alice", "email": "alice@example.com"}}
    return users.get(user_id)

# Without walrus - queries twice
user_id = 1
if find_user(user_id):
    user = find_user(user_id)
    print(f"User: {user}")

# With walrus - queries once
if (user := find_user(user_id)):
    print(f"User (walrus): {user}")

# List operations
print("\nList operations:")

numbers = [1, 2, 3, 4, 5]

# Without walrus - sum called multiple times
if sum(numbers) > 10:
    total = sum(numbers)
    avg = total / len(numbers)
    print(f"Average: {avg}")

# With walrus - sum called once
if (total := sum(numbers)) > 10:
    avg = total / len(numbers)
    print(f"Average (walrus): {avg}")

# File operations
print("\nFile operations:")

def read_config():
    print("  Reading config file...")
    return {"debug": True, "port": 8080, "host": "localhost"}

# Without walrus - reads twice
if "debug" in read_config():
    config = read_config()
    print(f"Debug enabled on {config['host']}:{config['port']}")

# With walrus - reads once
if (config := read_config()) and "debug" in config:
    print(f"Debug enabled (walrus) on {config['host']}:{config['port']}")

# JSON parsing
print("\nJSON parsing:")

import json

def parse_json(json_str):
    print(f"  Parsing JSON...")
    try:
        return json.loads(json_str)
    except:
        return None

json_str = '{"name": "Alice", "age": 30}'

# Without walrus - parses twice
if parse_json(json_str):
    data = parse_json(json_str)
    print(f"Name: {data.get('name')}")

# With walrus - parses once
if (data := parse_json(json_str)):
    print(f"Name (walrus): {data.get('name')}")

# API calls
print("\nAPI calls:")

def fetch_data(endpoint):
    print(f"  Fetching from {endpoint}...")
    return {"status": 200, "data": [1, 2, 3, 4, 5]}

# Without walrus - fetches twice
endpoint = "/api/users"
if fetch_data(endpoint).get("status") == 200:
    response = fetch_data(endpoint)
    print(f"Data: {response.get('data')}")

# With walrus - fetches once
if (response := fetch_data(endpoint)).get("status") == 200:
    print(f"Data (walrus): {response.get('data')}")

# Validation chains
print("\nValidation chains:")

def validate_input(value):
    print(f"  Validating {value}...")
    return value if value and len(value) >= 3 else None

user_input = "alice"

# Without walrus - validates multiple times
if validate_input(user_input):
    validated = validate_input(user_input)
    if len(validated) <= 10:
        final = validated.upper()
        print(f"Valid: {final}")

# With walrus - validates once
if (validated := validate_input(user_input)) and len(validated) <= 10:
    final = validated.upper()
    print(f"Valid (walrus): {final}")

# Practical example
print("\nPractical example:")

# Cache lookup
cache = {1: "cached_value_1"}

def compute_expensive(key):
    print(f"  Computing for key {key}...")
    return f"computed_value_{key}"

def get_or_compute(key):
    # Without walrus
    if key in cache:
        return cache[key]
    else:
        result = compute_expensive(key)
        cache[key] = result
        return result

# With walrus - cleaner
def get_or_compute_walrus(key):
    if (result := cache.get(key)) is not None:
        return result
    cache[key] = (result := compute_expensive(key))
    return result

print(f"Get 1: {get_or_compute_walrus(1)}")  # From cache
print(f"Get 2: {get_or_compute_walrus(2)}")  # Computed

# Form validation
def validate_email(email):
    print(f"  Validating email: {email}")
    return "@" in email and "." in email

def validate_age(age):
    print(f"  Validating age: {age}")
    return 0 < age < 150

email = "alice@example.com"
age = 30

# Without walrus - validates each twice
if validate_email(email) and validate_age(age):
    email_valid = validate_email(email)
    age_valid = validate_age(age)
    print(f"Email: {email_valid}, Age: {age_valid}")

# With walrus - validates once each
if (email_valid := validate_email(email)) and (age_valid := validate_age(age)):
    print(f"Email (walrus): {email_valid}, Age: {age_valid}")

  1. x ← 5

    1"""Walrus operator to avoid repeated calls"""23# Avoiding double computation4print("Avoiding double computation:")56def expensive_function(x):7    print(f"  Computing for {x}...")8    return x ** 3910# Without walrus - calls function twice11x→ 5 = 512if expensive_function(x) > 100:
    outputAvoiding double computation:
  2. def expensive_function(x):

    pass 1 of 3
    6def expensive_function(x5):7    print(f"  Computing for {x5}...")8    return x5 ** 3
    output  Computing for 5...
    All 3 passes — pass 1 is the card above
    passresult
    1
    2
    3125
  3. if expensive_function(x) > 100:

    11x = 512if expensive_function(x5) > 100:13    result = expensive_function(x5)14    print(f"Result: {result}")
  4. result ← 125

    12if expensive_function(x) > 100:13    result→ 125 = expensive_function(x5)14    print(f"Result: {result125}")
    outputResult: 125
  5. x ← 5

    16# With walrus - calls once17x→ 5 = 518if (result := expensive_function(x)) > 100:
  6. if (result := expensive_function(x)) > 100:

    17x = 518if (result125 := expensive_function(x5)) > 100:19    print(f"Result (walrus): {result125}")
    outputResult (walrus): 125
  7. text ← Hello World

    21# Method calls22print("\nMethod calls:")2324text→   Hello World   = "  Hello World  "
    output
    Method calls:
  8. cleaned ← Hello World

    26# Without walrus - strip called twice27if len(text  Hello World  .strip()) > 5:28    cleaned→ Hello World = text  Hello World  .strip()29    print(f"Cleaned: '{cleanedHello World}'")
    outputCleaned: 'Hello World'
  9. if len(cleaned := text.strip()) > 5:

    31# With walrus - strip called once32if len(cleanedHello World := text  Hello World  .strip()) > 5:33    print(f"Cleaned (walrus): '{cleanedHello World}'")
    outputCleaned (walrus): 'Hello World'
  10. text ← Error: File not found, pattern ← Error: (.*)

    35# Regex matching36print("\nRegex matching:")3738import re3940text→ Error: File not found = "Error: File not found"4142# Without walrus - match called twice43pattern→ Error: (.*) = r"Error: (.*)"44if re.match(pattern, text):
    output
    Regex matching:
  11. match ← <re.Match object; span=(0, 21), match='Error: File not found'>

    43pattern = r"Error: (.*)"44if re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(patternError: (.*), textError: File not found):45    match→ <re.Match object; span=(0, 21), match='Error: File not found'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(patternError: (.*), textError: File not found)46    print(f"Error message: {match<re.Match object; span=(0, 21), match='Error: File not found'>.group(1)}")
    outputError message: File not found
  12. if (match := re.match(pattern, text)):

    48# With walrus - match called once49if (match<re.Match object; span=(0, 21), match='Error: File not found'> := re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(patternError: (.*), textError: File not found)):50    print(f"Error message (walrus): {match<re.Match object; span=(0, 21), match='Error: File not found'>.group(1)}")
    outputError message (walrus): File not found
  13. user_id ← 1

    52# Database query53print("\nDatabase query:")5455def find_user(user_id):56    print(f"  Querying database for user {user_id}...")57    users = {1: {"name": "Alice", "email": "alice@example.com"}}58    return users.get(user_id)5960# Without walrus - queries twice61user_id→ 1 = 162if find_user(user_id):
    output
    Database query:
  14. users ← {1: {'name': 'Alice', 'email': 'alice@example.com'}}

    pass 1 of 3
    55def find_user(user_id1):56    print(f"  Querying database for user {user_id1}...")57    users→ {1: {'name': 'Alice', 'email': 'alice@example.com'}} = {1: {"name": "Alice", "email": "alice@example.com"}}58    return users{1: {'name': 'Alice', 'email': 'alice@example.com'}}.get(user_id1)
    output  Querying database for user 1...
    All 3 passes — pass 1 is the card above
    passuserusers
    1{1: {'name': 'Alice', 'email': 'alice@example.com'}}
    2{1: {'name': 'Alice', 'email': 'alice@example.com'}}
    3{'name': 'Alice', 'email': 'alice@example.com'}{1: {'name': 'Alice', 'email': 'alice@example.com'}}
  15. if find_user(user_id):

    61user_id = 162if find_user(user_id1):63    user = find_user(user_id1)64    print(f"User: {user}")
  16. user ← {'name': 'Alice', 'email': 'alice@example.com'}

    62if find_user(user_id):63    user→ {'name': 'Alice', 'email': 'alice@example.com'} = find_user(user_id1)64    print(f"User: {user{'name': 'Alice', 'email': 'alice@example.com'}}")
    outputUser: {'name': 'Alice', 'email': 'alice@example.com'}
  17. if (user := find_user(user_id)):

    66# With walrus - queries once67if (user{'name': 'Alice', 'email': 'alice@example.com'} := find_user(user_id1)):68    print(f"User (walrus): {user{'name': 'Alice', 'email': 'alice@example.com'}}")
    outputUser (walrus): {'name': 'Alice', 'email': 'alice@example.com'}
  18. numbers ← [1, 2, 3, 4, 5]

    70# List operations71print("\nList operations:")7273numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]
    output
    List operations:
  19. total ← 15, avg ← 3.0

    75# Without walrus - sum called multiple times76if sum(numbers[1, 2, 3, 4, 5]) > 10:77    total→ 15 = sum(numbers[1, 2, 3, 4, 5])78    avg→ 3.0 = total15 / len(numbers[1, 2, 3, 4, 5])79    print(f"Average: {avg3.0}")
    outputAverage: 3.0
  20. avg ← 3.0

    81# With walrus - sum called once82if (total15 := sum(numbers[1, 2, 3, 4, 5])) > 10:83    avg→ 3.0 = total15 / len(numbers[1, 2, 3, 4, 5])84    print(f"Average (walrus): {avg3.0}")
    outputAverage (walrus): 3.0
  21. print(" File operations:")

    86# File operations87print("\nFile operations:")
    output
    File operations:
  22. def read_config():

    pass 1 of 3
    89def read_config():90    print("  Reading config file...")91    return {"debug": True, "port": 8080, "host": "localhost"}
    output  Reading config file...
    All 3 passes — pass 1 is the card above
    passconfigconfig[’host’]config[’port’]
    1
    2
    3{'debug': True, 'port': 8080, 'host': 'localhost'}localhost8080
  23. config ← {'debug': True, 'port': 8080, 'host': 'localhost'}

    94if "debug" in read_config():95    config→ {'debug': True, 'port': 8080, 'host': 'localhost'} = read_config()96    print(f"Debug enabled on {config['host']localhost}:{config['port']8080}")
    outputDebug enabled on localhost:8080
  24. if (config := read_config()) and "debug" in config:

    98# With walrus - reads once99if (config{'debug': True, 'port': 8080, 'host': 'localhost'} := read_config()) and "debug" in config:100    print(f"Debug enabled (walrus) on {config['host']localhost}:{config['port']8080}")
    outputDebug enabled (walrus) on localhost:8080
  25. json_str ← {"name": "Alice", "age": 30}

    102# JSON parsing103print("\nJSON parsing:")104105import json106107def parse_json(json_str):108    print(f"  Parsing JSON...")109    try:110        return json.loads(json_str)111    except:112        return None113114json_str→ {"name": "Alice", "age": 30} = '{"name": "Alice", "age": 30}'
    output
    JSON parsing:
  26. def parse_json(json_str):

    pass 1 of 3
    107def parse_json(json_str{"name": "Alice", "age": 30}):108    print(f"  Parsing JSON...")109    try:
    output  Parsing JSON...
    All 3 passes — pass 1 is the card above
    passdata
    1
    2
    3{'name': 'Alice', 'age': 30}
  27. try:

    pass 1 of 3
    108print(f"  Parsing JSON...")109try:110    return json<module 'json' from '/usr/local/lib/python3.12/json/__init__.py'>.loads(json_str{"name": "Alice", "age": 30})111except:
    All 3 passes — pass 1 is the card above
    passdata
    1
    2
    3{'name': 'Alice', 'age': 30}
  28. if parse_json(json_str):

    116# Without walrus - parses twice117if parse_json(json_str{"name": "Alice", "age": 30}):118    data = parse_json(json_str{"name": "Alice", "age": 30})119    print(f"Name: {data.get('name')}")
  29. data ← {'name': 'Alice', 'age': 30}

    117if parse_json(json_str):118    data→ {'name': 'Alice', 'age': 30} = parse_json(json_str{"name": "Alice", "age": 30})119    print(f"Name: {data{'name': 'Alice', 'age': 30}.get('name')}")
    outputName: Alice
  30. if (data := parse_json(json_str)):

    121# With walrus - parses once122if (data{'name': 'Alice', 'age': 30} := parse_json(json_str{"name": "Alice", "age": 30})):123    print(f"Name (walrus): {data{'name': 'Alice', 'age': 30}.get('name')}")
    outputName (walrus): Alice
  31. endpoint ← /api/users

    125# API calls126print("\nAPI calls:")127128def fetch_data(endpoint):129    print(f"  Fetching from {endpoint}...")130    return {"status": 200, "data": [1, 2, 3, 4, 5]}131132# Without walrus - fetches twice133endpoint→ /api/users = "/api/users"134if fetch_data(endpoint).get("status") == 200:
    output
    API calls:
  32. def fetch_data(endpoint):

    pass 1 of 3
    128def fetch_data(endpoint/api/users):129    print(f"  Fetching from {endpoint/api/users}...")130    return {"status": 200, "data": [1, 2, 3, 4, 5]}
    output  Fetching from /api/users...
    All 3 passes — pass 1 is the card above
    passresponse
    1
    2
    3{'status': 200, 'data': [1, 2, 3, 4, 5]}
  33. if fetch_data(endpoint).get("status") == 200:

    133endpoint = "/api/users"134if fetch_data(endpoint/api/users).get("status") == 200:135    response = fetch_data(endpoint/api/users)136    print(f"Data: {response.get('data')}")
  34. response ← {'status': 200, 'data': [1, 2, 3, 4, 5]}

    134if fetch_data(endpoint).get("status") == 200:135    response→ {'status': 200, 'data': [1, 2, 3, 4, 5]} = fetch_data(endpoint/api/users)136    print(f"Data: {response{'status': 200, 'data': [1, 2, 3, 4, 5]}.get('data')}")
    outputData: [1, 2, 3, 4, 5]
  35. if (response := fetch_data(endpoint)).get("status") == 200:

    138# With walrus - fetches once139if (response{'status': 200, 'data': [1, 2, 3, 4, 5]} := fetch_data(endpoint/api/users)).get("status") == 200:140    print(f"Data (walrus): {response{'status': 200, 'data': [1, 2, 3, 4, 5]}.get('data')}")
    outputData (walrus): [1, 2, 3, 4, 5]
  36. user_input ← alice

    142# Validation chains143print("\nValidation chains:")144145def validate_input(value):146    print(f"  Validating {value}...")147    return value if value and len(value) >= 3 else None148149user_input→ alice = "alice"
    output
    Validation chains:
  37. def validate_input(value):

    pass 1 of 3
    145def validate_input(valuealice):146    print(f"  Validating {valuealice}...")147    return valuealice if value and len(value) >= 3 else None
    output  Validating alice...
    All 3 passes — pass 1 is the card above
    passuser_inputvalidatedfinal
    1alice
    2
    3alicealiceALICE
  38. if validate_input(user_input):

    151# Without walrus - validates multiple times152if validate_input(user_inputalice):153    validated = validate_input(user_inputalice)154    if len(validated) <= 10:
  39. validated ← alice

    152if validate_input(user_input):153    validated→ alice = validate_input(user_inputalice)154    if len(validated) <= 10:
  40. final ← ALICE

    153validated = validate_input(user_input)154if len(validatedalice) <= 10:155    final→ ALICE = validatedalice.upper()156    print(f"Valid: {finalALICE}")
    outputValid: ALICE
  41. final ← ALICE

    158# With walrus - validates once159if (validatedalice := validate_input(user_inputalice)) and len(validated) <= 10:160    final→ ALICE = validatedalice.upper()161    print(f"Valid (walrus): {finalALICE}")
    outputValid (walrus): ALICE
  42. cache ← {1: 'cached_value_1'}

    163# Practical example164print("\nPractical example:")165166# Cache lookup167cache→ {1: 'cached_value_1'} = {1: "cached_value_1"}168169def compute_expensive(key):170    print(f"  Computing for key {key}...")171    return f"computed_value_{key}"172173def get_or_compute(key):174    # Without walrus175    if key in cache:176        return cache[key]177    else:178        result = compute_expensive(key)179        cache[key] = result180        return result181182# With walrus - cleaner183def get_or_compute_walrus(key):184    if (result := cache.get(key)) is not None:185        return result186    cache[key] = (result := compute_expensive(key))187    return result188189print(f"Get 1: {get_or_compute_walrus(1)}")  # From cache190print(f"Get 2: {get_or_compute_walrus(2)}")  # Computed
    output
    Practical example:
  43. def get_or_compute_walrus(key):

    pass 1 of 2
    182# With walrus - cleaner183def get_or_compute_walrus(key1):184    if (result := cache.get(key)) is not None:185        return result
  44. if (result := cache.get(key)) is not None:

    183def get_or_compute_walrus(key):184    if (resultcached_value_1 := cache{1: 'cached_value_1'}.get(key1)) is not None:185        return resultcached_value_1186    cache[key] = (result := compute_expensive(key))
  45. print(f"Get 1: {get_or_compute_walrus(1)}") # From cache

    189print(f"Get 1: {get_or_compute_walrus(1)}")  # From cache190print(f"Get 2: {get_or_compute_walrus(2)}")  # Computed
    outputGet 1: cached_value_1
  46. def get_or_compute_walrus(key):

    pass 2 of 2
    182# With walrus - cleaner183def get_or_compute_walrus(key2):184    if (result := cache.get(key)) is not None:185        return result186    cache[key] = (resultNone := compute_expensive(key2))187    return result
  47. def compute_expensive(key):

    169def compute_expensive(key2):170    print(f"  Computing for key {key2}...")171    return f"computed_value_{key2}"
    output  Computing for key 2...
  48. result ← computed_value_2, cache[key] ← computed_value_2

    185    return result186cache[key]→ computed_value_2 = (result→ computed_value_2 := compute_expensive(key2))187return resultcomputed_value_2
  49. email ← alice@example.com, age ← 30

    189print(f"Get 1: {get_or_compute_walrus(1)}")  # From cache190print(f"Get 2: {get_or_compute_walrus(2)}")  # Computed191192# Form validation193def validate_email(email):194    print(f"  Validating email: {email}")195    return "@" in email and "." in email196197def validate_age(age):198    print(f"  Validating age: {age}")199    return 0 < age < 150200201email→ alice@example.com = "alice@example.com"202age→ 30 = 30
    outputGet 2: computed_value_2
  50. def validate_email(email):

    pass 1 of 3
    192# Form validation193def validate_email(emailalice@example.com):194    print(f"  Validating email: {emailalice@example.com}")195    return "@" in emailalice@example.com and "." in email
    output  Validating email: alice@example.com
    All 3 passes — pass 1 is the card above
    passageemail_validage_valid
    130
    2
    330TrueTrue
  51. def validate_age(age):

    pass 1 of 3
    197def validate_age(age30):198    print(f"  Validating age: {age30}")199    return 0 < age30 < 150
    output  Validating age: 30
    All 3 passes — pass 1 is the card above
    passemailemail_validage_valid
    1alice@example.com
    2
    3alice@example.comTrueTrue
  52. if validate_email(email) and validate_age(age):

    204# Without walrus - validates each twice205if validate_email(emailalice@example.com) and validate_age(age30):206    email_valid = validate_email(emailalice@example.com)207    age_valid = validate_age(age)
  53. email_valid ← True

    205if validate_email(email) and validate_age(age):206    email_valid→ True = validate_email(emailalice@example.com)207    age_valid = validate_age(age30)208    print(f"Email: {email_valid}, Age: {age_valid}")
  54. age_valid ← True

    206email_valid = validate_email(email)207age_valid→ True = validate_age(age30)208print(f"Email: {email_validTrue}, Age: {age_validTrue}")
    outputEmail: True, Age: True
  55. if (email_valid := validate_email(email)) and (age_valid := validate_a…

    210# With walrus - validates once each211if (email_validTrue := validate_email(emailalice@example.com)) and (age_validTrue := validate_age(age30)):212    print(f"Email (walrus): {email_validTrue}, Age: {age_validTrue}")
    outputEmail (walrus): True, Age: True

Any time you find yourself calling the same function twice to check and use a result, consider the walrus operator.

call elimination Using `:=` to call a function once and reuse its result, avoiding duplicate expensive operations like database queries or API calls.

When Not to Use

walrus_pitfalls.py
Replay: real traced execution (multi-file project)
"""When not to use walrus operator"""

# Reduces readability
print("Reduces readability:")

# Bad - too complex
numbers = [1, 2, 3, 4, 5]
result = [y for x in numbers if (y := x * 2) > 5 if (z := y + 1) < 15]
print(f"Complex walrus: {result}")

# Better - split into steps
doubled = [x * 2 for x in numbers]
filtered = [y for y in doubled if y > 5 and y + 1 < 15]
print(f"Clear steps: {filtered}")

# Unnecessary complexity
print("\nUnnecessary complexity:")

# Bad - walrus adds no value
if (x := 5) == 5:
    print(f"x is {x}")

# Better - simple assignment
x = 5
if x == 5:
    print(f"x is {x}")

# Simple assignments
print("\nSimple assignments:")

# Bad - walrus not needed
data = [1, 2, 3]
if (length := len(data)) > 0:
    print(f"Has {length} items")

# Better - separate lines when not reusing
if len(data) > 0:
    print(f"Has {len(data)} items")

# Good use - value reused
if (length := len(data)) > 0:
    average = sum(data) / length
    print(f"Average of {length} items: {average}")

# Mutation confusion
print("\nMutation confusion:")

# Bad - unclear what's being assigned
items = [1, 2, 3]
if (items := items + [4]) and len(items) > 3:
    print(f"Items: {items}")

# Better - explicit mutation
items = [1, 2, 3]
items = items + [4]
if len(items) > 3:
    print(f"Items: {items}")

# Debugging difficulty
print("\nDebugging difficulty:")

# Bad - hard to debug
def process(x):
    return x * 2

numbers = [1, 2, 3, 4, 5]
if any((result := process(n)) > 5 for n in numbers):
    print(f"Found: {result}")  # Which result?

# Better - explicit loop
for n in numbers:
    result = process(n)
    if result > 5:
        print(f"Found: {result}")
        break

# Scope confusion
print("\nScope confusion:")

# Bad - walrus creates variable in outer scope
data = [1, 2, 3, 4, 5]
evens = [x for x in data if (is_even := x % 2 == 0)]
print(f"Last is_even value: {is_even}")  # Unexpected side effect

# Better - keep scope clear
evens = [x for x in data if x % 2 == 0]
print(f"Evens: {evens}")

# Multiple assignments
print("\nMultiple assignments:")

# Bad - trying to assign multiple values
try:
    if (a := 1, b := 2):  # Syntax error
        pass
except SyntaxError:
    print("Cannot use multiple := in one expression")

# Better - separate assignments
a, b = 1, 2
if a and b:
    print(f"a={a}, b={b}")

# Class attributes
print("\nClass attributes:")

# Bad - walrus in class definition
class BadExample:
    # This doesn't work as expected
    # value = (cached := compute())
    pass

# Better - regular assignment
class GoodExample:
    def __init__(self):
        self.value = self.compute()

    def compute(self):
        return 42

obj = GoodExample()
print(f"Value: {obj.value}")

# Performance misconception
print("\nPerformance misconception:")

# Bad - thinking walrus improves performance
numbers = list(range(50))
# Walrus doesn't make this faster
total = sum(n for n in numbers if (doubled := n * 2) > 500)

# Better - same speed, clearer
total = sum(n * 2 for n in numbers if n * 2 > 500)
print(f"Total: {total}")

# When walrus is good
print("\nWhen walrus is good:")

# Good: Avoid repeated expensive calls
def expensive():
    return 42

if (result := expensive()) > 40:
    print(f"Good use: {result}")

# Good: Capture match object
import re
text = "Error: Something failed"
if (match := re.search(r"Error: (.*)", text)):
    print(f"Good use: {match.group(1)}")

# Good: Read lines
lines = iter(["line 1", "line 2", ""])
while (line := next(lines, None)) and line:
    print(f"Good use: {line}")

# Best practices
print("\nBest practices:")

# DO use walrus when:
# 1. Avoiding repeated expensive calls
def fetch_data():
    return {"value": 100}

if (data := fetch_data()).get("value", 0) > 50:
    print(f"✓ Data: {data}")

# 2. Capturing intermediate values in comprehensions
numbers = [1, 2, 3, 4, 5]
squares = [sq for n in numbers if (sq := n * n) > 10]
print(f"✓ Squares: {squares}")

# DON'T use walrus when:
# 1. Simple assignments suffice
x = 10  # Not: if (x := 10)
print(f"✓ Simple: {x}")

# 2. Reduces readability
# Not: if (a := b := c := 1)
a = b = c = 1
print(f"✓ Clear: a={a}")

# 3. In complex nested expressions
# Keep it simple!

  1. numbers ← [1, 2, 3, 4, 5], y ← 10, z ← 11, result ← [6, 8, 10]

    1"""When not to use walrus operator"""23# Reduces readability4print("Reduces readability:")56# Bad - too complex7numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]8result→ [6, 8, 10] = [y→ 10 for x in numbers[1, 2, 3, 4, 5] if (y := x * 2) > 5 if (z→ 11 := y + 1) < 15]9print(f"Complex walrus: {result[6, 8, 10]}")1011# Better - split into steps12doubled→ [2, 4, 6, 8, 10] = [x * 2 for x in numbers[1, 2, 3, 4, 5]]13filtered→ [6, 8, 10] = [y for y in doubled[2, 4, 6, 8, 10] if y > 5 and y + 1 < 15]14print(f"Clear steps: {filtered[6, 8, 10]}")1516# Unnecessary complexity17print("\nUnnecessary complexity:")
    outputReduces readability:
    Complex walrus: [6, 8, 10]
    Clear steps: [6, 8, 10]
    
    Unnecessary complexity:
  2. if (x := 5) == 5:

    19# Bad - walrus adds no value20if (x5 := 5) == 5:21    print(f"x is {x5}")
    outputx is 5
  3. x ← 5

    23# Better - simple assignment24x→ 5 = 525if x == 5:
  4. if x == 5:

    24x = 525if x5 == 5:26    print(f"x is {x5}")
    outputx is 5
  5. data ← [1, 2, 3]

    28# Simple assignments29print("\nSimple assignments:")3031# Bad - walrus not needed32data→ [1, 2, 3] = [1, 2, 3]33if (length := len(data)) > 0:
    output
    Simple assignments:
  6. if (length := len(data)) > 0:

    32data = [1, 2, 3]33if (length3 := len(data[1, 2, 3])) > 0:34    print(f"Has {length3} items")
    outputHas 3 items
  7. if len(data) > 0:

    36# Better - separate lines when not reusing37if len(data[1, 2, 3]) > 0:38    print(f"Has {len(data[1, 2, 3])} items")
    outputHas 3 items
  8. average ← 2.0

    40# Good use - value reused41if (length3 := len(data[1, 2, 3])) > 0:42    average→ 2.0 = sum(data[1, 2, 3]) / length343    print(f"Average of {length3} items: {average2.0}")
    outputAverage of 3 items: 2.0
  9. items ← [1, 2, 3]

    45# Mutation confusion46print("\nMutation confusion:")4748# Bad - unclear what's being assigned49items→ [1, 2, 3] = [1, 2, 3]50if (items := items + [4]) and len(items) > 3:
    output
    Mutation confusion:
  10. if (items := items + [4]) and len(items) > 3:

    49items = [1, 2, 3]50if (items[1, 2, 3, 4] := items + [4]) and len(items) > 3:51    print(f"Items: {items[1, 2, 3, 4]}")
    outputItems: [1, 2, 3, 4]
  11. items ← [1, 2, 3]

    53# Better - explicit mutation54items→ [1, 2, 3] = [1, 2, 3]55items→ [1, 2, 3, 4] = items + [4]56if len(items) > 3:
  12. if len(items) > 3:

    55items = items + [4]56if len(items[1, 2, 3, 4]) > 3:57    print(f"Items: {items[1, 2, 3, 4]}")
    outputItems: [1, 2, 3, 4]
  13. numbers ← [1, 2, 3, 4, 5]

    59# Debugging difficulty60print("\nDebugging difficulty:")6162# Bad - hard to debug63def process(x):64    return x * 26566numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]67if any((result := process(n)) > 5 for n in numbers):
    output
    Debugging difficulty:
  14. def process(x):

    pass 1 of 6
    62# Bad - hard to debug63def process(x1):64    return x1 * 2
    All 6 passes — pass 1 is the card above
    passxresultnumbers
    11
    22
    336[1, 2, 3, 4, 5]
    41
    52
    63
  15. if any((result := process(n)) > 5 for n in numbers):

    66numbers = [1, 2, 3, 4, 5]67if any((result6 := process(n)) > 5 for n in numbers[1, 2, 3, 4, 5]):68    print(f"Found: {result6}")  # Which result?
    outputFound: 6
  16. for n in numbers:

    pass 1 of 3
    70# Better - explicit loop71for n1 in numbers[1, 2, 3, 4, 5]:72    result = process(n1)73    if result > 5:
    All 3 passes — pass 1 is the card above
    passn
    11
    22
    33
  17. result ← 2

    71for n in numbers:72    result→ 2 = process(n1)73    if result > 5:
  18. result ← 4

    71for n in numbers:72    result→ 4 = process(n2)73    if result > 5:
  19. result ← 6

    71for n in numbers:72    result→ 6 = process(n3)73    if result > 5:
  20. if result > 5:

    72result = process(n)73if result6 > 5:74    print(f"Found: {result6}")75    break
    outputFound: 6
  21. data ← [1, 2, 3, 4, 5], is_even ← False, evens ← [2, 4]

    77# Scope confusion78print("\nScope confusion:")7980# Bad - walrus creates variable in outer scope81data→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]82evens→ [2, 4] = [x for x in data[1, 2, 3, 4, 5] if (is_even→ False := x % 2 == 0)]83print(f"Last is_even value: {is_evenFalse}")  # Unexpected side effect8485# Better - keep scope clear86evens→ [2, 4] = [x for x in data[1, 2, 3, 4, 5] if x % 2 == 0]87print(f"Evens: {evens[2, 4]}")8889# Multiple assignments90print("\nMultiple assignments:")
    output
    Scope confusion:
    Last is_even value: False
    Evens: [2, 4]
    
    Multiple assignments:
  22. if (a := 1, b := 2): # Syntax error

    93try:94    if (a1 := 1, b2 := 2):  # Syntax error95        pass96except SyntaxError:
  23. a ← 1, b ← 2

    99# Better - separate assignments100a→ 1, b→ 2 = 1, 2101if a and b:
  24. if a and b:

    100a, b = 1, 2101if a1 and b2:102    print(f"a={a1}, b={b2}")
    outputa=1, b=2
  25. print(" Class attributes:")

    104# Class attributes105print("\nClass attributes:")106107# Bad - walrus in class definition108class BadExample:109    # This doesn't work as expected110    # value = (cached := compute())111    pass112113# Better - regular assignment114class GoodExample:115    def __init__(self):116        self.value = self.compute()117    118    def compute(self):119        return 42120121obj = GoodExample()122print(f"Value: {obj.value}")
    output
    Class attributes:
  26. def __init__(self):

    114class GoodExample:115    def __init__(self⟨GoodExample A⟩):116        self.value = self⟨GoodExample A⟩.compute()
  27. def compute(self):

    118def compute(self⟨GoodExample A⟩):119    return 42
  28. self.value ← 42, obj ← ⟨GoodExample A⟩, numbers ← [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]

    115    def __init__(self):116        self.value→ 42 = self⟨GoodExample A⟩.compute()117    118    def compute(self):119        return 42120121obj→ ⟨GoodExample A⟩ = GoodExample()122print(f"Value: {obj.value42}")123124# Performance misconception125print("\nPerformance misconception:")126127# Bad - thinking walrus improves performance128numbers→ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49] = list(range(50))129# Walrus doesn't make this faster130total→ 0 = sum(n for n in numbers[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49] if (doubled→ 98 := n * 2) > 500)131132# Better - same speed, clearer133total→ 0 = sum(n * 2 for n in numbers[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49] if n * 2 > 500)134print(f"Total: {total0}")135136# When walrus is good137print("\nWhen walrus is good:")
    outputValue: 42
    
    Performance misconception:
    Total: 0
    
    When walrus is good:
  29. if (result := expensive()) > 40:

    143if (result42 := expensive()) > 40:144    print(f"Good use: {result42}")
    outputGood use: 42
  30. text ← Error: Something failed

    147import re148text→ Error: Something failed = "Error: Something failed"149if (match := re.search(r"Error: (.*)", text)):
  31. if (match := re.search(r"Error: (.*)", text)):

    148text = "Error: Something failed"149if (match<re.Match object; span=(0, 23), match='Error: Something failed'> := re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"Error: (.*)", textError: Something failed)):150    print(f"Good use: {match<re.Match object; span=(0, 23), match='Error: Something failed'>.group(1)}")
    outputGood use: Something failed
  32. lines ← ⟨list_iterator B⟩

    152# Good: Read lines153lines→ ⟨list_iterator B⟩ = iter(["line 1", "line 2", ""])154while (line := next(lines, None)) and line:
  33. while (line := next(lines, None)) and line:

    pass 1 of 2
    153lines = iter(["line 1", "line 2", ""])154while (lineline 1 := next(lines⟨list_iterator B⟩, None)) and line:155    print(f"Good use: {lineline 1}")
    outputGood use: line 1
  34. while (line := next(lines, None)) and line:

    pass 2 of 2
    153lines = iter(["line 1", "line 2", ""])154while (lineline 2 := next(lines⟨list_iterator B⟩, None)) and line:155    print(f"Good use: {lineline 2}")
    outputGood use: line 2
  35. print(" Best practices:")

    157# Best practices158print("\nBest practices:")
    output
    Best practices:
  36. if (data := fetch_data()).get("value", 0) > 50:

    165if (data{'value': 100} := fetch_data()).get("value", 0) > 50:166    print(f"✓ Data: {data{'value': 100}}")
    output✓ Data: {'value': 100}
  37. numbers ← [1, 2, 3, 4, 5], sq ← 25, squares ← [16, 25], x ← 10

    168# 2. Capturing intermediate values in comprehensions169numbers→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]170squares→ [16, 25] = [sq→ 25 for n in numbers[1, 2, 3, 4, 5] if (sq := n * n) > 10]171print(f"✓ Squares: {squares[16, 25]}")172173# DON'T use walrus when:174# 1. Simple assignments suffice175x→ 10 = 10  # Not: if (x := 10)176print(f"✓ Simple: {x10}")177178# 2. Reduces readability179# Not: if (a := b := c := 1)180a→ 1 = b→ 1 = c→ 1 = 1181print(f"✓ Clear: a={a1}")
    output✓ Squares: [16, 25]
    ✓ Simple: 10
    ✓ Clear: a=1

The walrus operator is a tool for specific situations. Overusing it makes code harder to read and debug.

walrus pitfalls Cases where the walrus operator reduces readability or adds unnecessary complexity, including simple assignments and nested expressions.

Use Cases

  • Avoid repeated function calls in conditions
  • Capture values in comprehensions
  • Simplify file and stream reading loops
  • Debug intermediate values
  • Reduce temporary variable clutter

Exercise: walrus_practice.py

Refactor a function that calls len() twice (once for check, once for use) to use the walrus operator