|
1 | | -#TODO: Add about for this concept. |
| 1 | +# About |
2 | 2 |
|
| 3 | +Added in Python 3.8, assignment expressions use the `:=` operator, popularly called the ["walrus operator"][whats-new]. |
| 4 | + |
| 5 | +The central idea is that a variable can be assigned within the context of another statement. |
| 6 | +A simple example is when something tested in a condition is needed again within the body of an `if` statement: |
| 7 | + |
| 8 | +```python |
| 9 | +# without walrus operator |
| 10 | +a = 'short' |
| 11 | +if len(a) < 10: |
| 12 | + print(f"{len(a)} characters is too short") |
| 13 | + |
| 14 | +# => "5 characters is too short" |
| 15 | + |
| 16 | +# with walrus operator |
| 17 | +# Note the parentheses around the assignment (necessary) |
| 18 | +if (n := len(a)) < 10: |
| 19 | + print(f"{n} characters is too short") |
| 20 | + |
| 21 | +# => "5 characters is too short" |
| 22 | +``` |
| 23 | + |
| 24 | +Thus, setting the `n` variable saves calculating `len(a)` twice. |
| 25 | +The saving is fairly trivial in this case, but becomes significant for a more expensive operation such as file I/O: |
| 26 | + |
| 27 | +```python |
| 28 | +# Loop over fixed length blocks |
| 29 | +while (block := f.read(256)) != '': |
| 30 | + process(block) |
| 31 | +``` |
| 32 | + |
| 33 | +## Use cases |
| 34 | + |
| 35 | +The walrus operator was [controversial][controversy] in the Python community when [first introduced][pep-572] in 2018. |
| 36 | +It is now an established part of the core language, simplifying code in some particular situations, but should not be over-used. |
| 37 | +As so often in programming, we should consider if use of a feature increases or decreases the readability of the code. |
| 38 | + |
| 39 | +Some applications of the walrus operator are listed below. |
| 40 | + |
| 41 | +### Comprehensions |
| 42 | + |
| 43 | +List comprehensions, dictionary comprehensions, generator expressions, _etc_, all allow Python to do a lot in a terse piece of code. |
| 44 | + |
| 45 | +Including a walrus operator can _sometimes_ make such code shorter and clearer, especially if a value calculated in the `if` clause is also needed in other parts of the comprehension. |
| 46 | + |
| 47 | +```python |
| 48 | +[clean_name.title() for name in names |
| 49 | + if (clean_name := name.strip().lower()) in allowed_names] |
| 50 | +``` |
| 51 | + |
| 52 | +Note that the calculated value `clean_name` is only in scope within the comprehension. |
| 53 | +It cannot be used in other parts of the program. |
| 54 | + |
| 55 | +### RegEx matching |
| 56 | + |
| 57 | +Use of the walrus operator can simplify nested `if...else` statements. |
| 58 | +Handling regular expression matches is [an example][walrus-blog] of this: |
| 59 | + |
| 60 | +```python |
| 61 | +import re |
| 62 | + |
| 63 | +test = "Something we want to search" |
| 64 | +pattern1 = r"^.*(thing).*" |
| 65 | +pattern2 = r"^.*(missing).*" |
| 66 | + |
| 67 | +# without walrus |
| 68 | +m = re.match(pattern1, test) |
| 69 | +if m: |
| 70 | + print(f"Matched the 1st pattern: {m.group(1)}") |
| 71 | +else: |
| 72 | + m = re.match(pattern2, test) |
| 73 | + if m: |
| 74 | + print(f"Matched the 2nd pattern: {m.group(1)}") |
| 75 | +# => "Matched 1st pattern: 'thing'" |
| 76 | + |
| 77 | +# Cleaner with walrus |
| 78 | +if m := (re.match(pattern1, test)): |
| 79 | + print(f"Matched 1st pattern: '{m.group(1)}'") |
| 80 | +elif m := (re.match(pattern2, test)): |
| 81 | + print(f"Matched 2nd pattern: '{m.group(1)}'") |
| 82 | +# => "Matched 1st pattern: 'thing'" |
| 83 | +``` |
| 84 | + |
| 85 | +### Inside f-strings |
| 86 | + |
| 87 | +This is not a particularly common use of walrus operators, but it can sometimes simplify code. |
| 88 | +As usual, the assignment must be within parentheses. |
| 89 | + |
| 90 | +```python |
| 91 | +from datetime import datetime |
| 92 | + |
| 93 | +print(f"Today is: {(today:=datetime.today()):%Y-%m-%d}, which is {today:%A}") |
| 94 | + |
| 95 | +# => "Today is: 2024-01-06, which is Saturday" |
| 96 | +``` |
| 97 | + |
| 98 | +[whats-new]: https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions |
| 99 | +[walrus-blog]: https://martinheinz.dev/blog/79 |
| 100 | +[pep-572]: https://peps.python.org/pep-0572/ |
| 101 | +[controversy]: https://dev.to/renegadecoder94/the-controversy-behind-the-walrus-operator-in-python-4k4e |
0 commit comments