forked from huangsam/ultimate-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwalrus_operator.py
More file actions
121 lines (99 loc) · 4.96 KB
/
walrus_operator.py
File metadata and controls
121 lines (99 loc) · 4.96 KB
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
The walrus operator, also known as the assignment expression operator,
allows you to assign values to variables as part of an expression. This
feature was introduced in Python 3.8 through PEP 572.
The walrus operator uses the := syntax and is particularly useful in
reducing redundancy when you need to compute a value and then use it
in a condition or comprehension.
"""
def main() -> None:
# Traditional approach: compute a value and check it separately
# Let's say we want to check if a string has more than 5 characters
text = "Hello, Python!"
length = len(text)
if length > 5:
assert length == 14
# With the walrus operator, we can assign and check in one expression.
# This is cleaner and avoids repeating the computation or storing
# intermediate variables unnecessarily
text2 = "Ultimate"
if (length2 := len(text2)) > 5:
# The walrus operator assigned len(text2) to length2 AND returned it
# for the comparison, all in the same line
assert length2 == 8
# The walrus operator is especially powerful in while loops. Here's a
# traditional approach that requires reading input twice
numbers_old = []
n = int("5") # Simulating user input
while n != 0:
numbers_old.append(n)
n = int("0") # Simulating next input
assert numbers_old == [5]
# With the walrus operator, we can assign and check in the loop condition.
# This is more concise and avoids the duplication of the input reading logic
numbers_new = []
inputs = ["3", "7", "0"] # Simulating a sequence of inputs
index = 0
# Note: In a real scenario, you'd read from input() instead of a list
def get_next_input():
nonlocal index
if index < len(inputs):
result = int(inputs[index])
index += 1
return result
return 0
while (num := get_next_input()) != 0:
# The walrus operator assigns get_next_input() to num and checks if it's not 0
numbers_new.append(num)
assert numbers_new == [3, 7]
# Ensure the function returns 0 when no more inputs
assert get_next_input() == 0
# The walrus operator shines in list comprehensions when you need to
# compute a value once and reuse it. Without walrus, you'd either:
# 1. Compute the value multiple times (inefficient)
# 2. Use a for loop instead of comprehension (less elegant)
data = ["apple", "banana", "cherry", "date"]
# Traditional approach: computing len() twice per item is wasteful
long_words_old = [word for word in data if len(word) > 5 and len(word) < 7]
assert long_words_old == ["banana", "cherry"]
# With walrus operator: compute len() once and reuse the result
# The walrus operator assigns len(word) to word_len, which we can
# then use multiple times in the same comprehension
long_words_new = [word for word in data if 5 < (word_len := len(word)) < 7]
assert long_words_new == ["banana", "cherry"]
# The walrus operator can be used in comprehensions to filter and transform
# data simultaneously. Here we square numbers but only keep those where
# the square is less than 50
numbers = [3, 5, 7, 9, 11]
# Without walrus: we'd need to compute the square twice or use a for loop
squares_old = [n * n for n in numbers if n * n < 50]
assert squares_old == [9, 25, 49]
# With walrus: compute the square once, store it, and use it
# This is both more efficient and clearer about the intent
squares_new = [square for n in numbers if (square := n * n) < 50]
assert squares_new == [9, 25, 49]
# The walrus operator works in set comprehensions too
# Let's find unique word lengths greater than 4
words = ["hi", "hello", "world", "python", "code"]
# With walrus operator in a set comprehension
long_lengths = {word_len for word in words if (word_len := len(word)) > 4}
assert long_lengths == {5, 6}
# And in dictionary comprehensions as well
# Create a dict of words to their lengths, but only for words > 4 chars
word_length_map = {word: word_len for word in words if (word_len := len(word)) > 4}
assert word_length_map == {"hello": 5, "world": 5, "python": 6}
# Important note: The walrus operator creates variables in the enclosing scope.
# This means variables assigned with := inside a comprehension are accessible
# outside of it (unlike traditional loop variables in comprehensions)
[result for x in [1, 2, 3] if (result := x * 2) > 2]
# The variable 'result' is now accessible here, with its last assigned value
assert result == 6
# The walrus operator can be nested, though this can reduce readability
# Use nesting sparingly and only when it genuinely improves the code
values = [1, 2, 3, 4, 5]
if (total := sum(doubled := [x * 2 for x in values])) > 15:
# Here 'doubled' is assigned inside the expression for 'total'
assert doubled == [2, 4, 6, 8, 10]
assert total == 30
if __name__ == "__main__":
main()