/Walrus-Operator-Use-Cases

Walrus operator has been added in Python 3.8 and offer a plethora of possibilities.

The UnlicenseUnlicense

Walrus Operator Use Cases

Walrus Operator (aka Assignement expression) has been added in Python 3.8.

There is new syntax := that assigns values to variables as part of a larger expression. It is affectionately known as “the walrus operator” due to its resemblance to the eyes and tusks of a walrus. Source: What's New In Python 3.8

Avoid double calls

Reuse a value from if statement

if (n:= len(foo)) > 10:
    print(f"foo is too long. Size of foo : {n}")
    
# OR

group = match.group(1) if (match := re.match(data)) else None

Instead of

if (len(foo)) > 10:
    print(f"foo is too long. Size of foo : {len(foo)}")

It is important to note that Walrus operator does not introduce a new scope.

if (n:= len(foo)) > 10:
    print(f"foo is too long.")
print(f"Size of foo : {n}")

Reuse a value in a list

foo = [y:= f(x), y**2, y**3]

Instead of

foo = [f(x), f(x)**2, f(x)**3]

Reuse a value from a condition in a list comprehension

results = [ y for x in data if (y:=f(x))]

Instead of

results = []
for x in data:
    result = f(x)
    if result:
        results.append(result)

Avoid nested if statements

if y:= re.match("str1", x):
    print(f"Match the 1st string: {y.match(0)}")
elif y:= re.match("str2", x):
    print(f"Match the 2nd string: {y.match(0)}")
    
# OR USING SHORT CIRCUITING

if y := (re.match('str1', x) or re.match('str2', x)):
    print(f'match: {y.group(0)}')

More info about short-circuiting

Instead of

y = re.match("str1", x)
if y:
    print(f"Match the 1st string: {y.match(0)}")
else:
    y = re.match("str2", x)
    if y:
        print(f"Match the 2nd string: {y.match(0)}")

Read within while-loops (or Do-loops)

while (block := f.read(256)) != '':
    process(block)

# OR

while (command := input("> ")) != "quit":
    print("You entered:", command)

Instead of

while True:
    stuff()
    if fail_condition:
        break

# OR

stuff()
while not fail_condition():
    stuff()

Use a subtotal value as you go

values = 1, 2, 3, 4
total = 0
[total := total + value for value in values]
# [1, 3, 6, 10]

Use it as a key & as a value in dict declaration

names = "str1 str2", "str3 str4"
{ (n := name.lower()): n.split() for name in names}
# {'str1 str2': ['str1', 'str2'], 'str3 str4': ['str3', 'str4']}

Filter data

filtered_data = [y for x in data if (y := f(x)) is not None]

Instead of

filtered_data = list(filter(lambda y: y is not None, map(f, data)))

Warning

You should not use Walrus operator in a with statement.

# INVALID, SHOULD BE AVOIDED
with (f := open('file.txt')):
    for l in f:
        print(f)

Keep doing

with open('file.txt') as f:
    for l in f:
        print(f)

Stay Zen

Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Source: The Zen of Python

Please read the PEP 572 for more information about what is valid/invalid.

How to contribute

To add a use case, please create an issue with the Propose a Use Case template. It would be discussed and added.

Sources: