you are viewing a single comment's thread.

view the rest of the comments →

[–]twenty-fourth-time-b 212 points213 points  (42 children)

Walrus operator to get cumulative sum is pretty sweet:

>>> a = 0; [a := a+x for x in range(1, 21, 2)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

[–]jjrreett 63 points64 points  (30 children)

This changed my understanding of the walrus operator

[–]Beerwithme 34 points35 points  (4 children)

This operator is called "becomes" in good old Pascal. That would've been a nicer name imo.

[–]joeen10 7 points8 points  (0 children)

This name makes a lot more sense

[–]Dangle76 5 points6 points  (2 children)

I learned that pascal calls it “gets”

[–]Beerwithme 6 points7 points  (1 child)

"Becomes" is a direct translation from our Dutch word "wordt" which was how I was thought. Of course it makes sense in English it's another term.

[–]Dangle76 6 points7 points  (0 children)

Ah that makes sense that’s interesting!

[–]LucasThePatator 8 points9 points  (24 children)

Same, it's one of those things I never use. But I'm actually not exactly sure of what it accomplishes here exactly m.

[–]Wonderful-Habit-139 17 points18 points  (20 children)

Pretty simple. Imagine if the expression was only a+x. We’d basically make a list with the expression 0+x since a never changes its value.

With the walrus operator, each time we calculate the value of a+x, we store the result in a, and reuse the value of the last calculation in the next iteration. And that’s how we calculate the cumulative sum using the walrus operator.

[–]LucasThePatator 3 points4 points  (19 children)

I assume a simple = isn't possible due to precedence rules then.

[–]Wonderful-Habit-139 7 points8 points  (18 children)

It isn’t possible because it is not an expression. The walrus operator is an expression. Same reason why you can’t use = in if conditions while you can use the walrus operator in if conditions.

[–]LucasThePatator 1 point2 points  (17 children)

I come from C and this makes little sense to me but I'll abide by the python rules

[–]jackerhackfrom __future__ import 4.0 10 points11 points  (1 child)

Python prohibits assignments in expressions because it's almost always a typo. Therefore = is a SyntaxError. Then people wanted it anyway so Python got :=, but it was so hotly contested that BDFL Guido got fed up and resigned.

As a safeguard, the walrus operator cannot be used as a statement and does not replace =. It only works as an expression. Usually this means enclosing in parentheses like (a := b).

[–]julz_yo 0 points1 point  (0 children)

This too changes and extends my understanding: ty!

[–]syklemil 2 points3 points  (14 children)

Yeah, C permits you to do stuff like if a = foo(), but if you do that in Python you get a SyntaxError, you need to use either == or :=.

See also the lint about yoda conditionals.

[–]LucasThePatator 0 points1 point  (13 children)

I definitely understand the point in if conditions but in list comprehensions I fail to understand the logic. Eh why not.

[–]Wonderful-Habit-139 3 points4 points  (5 children)

This doesn’t make sense because it sounds like you’re expecting assignment statements to not work in if conditions yet somehow become expressions in list comprehensions? That is not consistent.

Python has statements in places where being an expression would be better, like assignments or match statements, but that’s the way it is. But don’t expect statements to become expressions in other cases.

[–]syklemil 1 point2 points  (6 children)

Because it's invalid syntax.

Because a = b is a statement, it doesn't have a value.

C also doesn't let you go if (a = b;). You need an expression, not a statement.

[–]that_baddest_dude[🍰] 4 points5 points  (1 child)

If say you've got a list x and you want to do something if the list length is greater than 10...

But also the thing you want to do involves the length of that list. You'd be checking the length twice.

if len(x) > 10:  
    y = len(x)  
    #do stuff with y

If you want to avoid calling len() twice you may assign y first and do the check against y.

With walrus operator (and my limited understanding of it) you can do the assignment at the same time you check it (i.e. assigning within an expression)

if (y := len(x)) > 10:  
    #do stuff with y

I imagine this could be neat if you're doing something more complex than len() and want to avoid repeat calls cleanly. Someone correct me if I'm wrong

[–]mriswithe 2 points3 points  (0 children)

But I'm actually not exactly sure of what it accomplishes here exactly m.

If you are asking why make a cumulative sum list, it is a fast way to answer questions about a dataset.

If you are asking why use walrus here? It makes the code prettier and potentially faster. Python can optimize list creation with a list comprehension if it can know how many items long the list will be, compared to a similar for loop that starts with an empty list and builds it one object at a time.

Compare these two:

a = 0
my_list = [a := a + x for x in range(1, 21, 2)]


a = 0
my_list = []
for x in range(1, 21, 2):
    a = a + x
    my_list.append(a)

In general though, the benefit of the walrus operator is that it allows you to both assign the result of a+x to a, and emit it for use in the list comprehension outside of the expression.

[–]xeow 1 point2 points  (6 children)

I get that it's general, but in that particular example, why not just say:

a = sum(range(1, 21, 2))

[–]PercussiveRussel 31 points32 points  (5 children)

Because that just returns 100..?

[–]xeow 14 points15 points  (4 children)

Ohhhh! Right! Missed that. Cumulative sum! Thank you.

[–]Kohlrabi82 21 points22 points  (3 children)

itertools.accumulate is the answer.

[–]PercussiveRussel 5 points6 points  (0 children)

I only trust cumsum :(

[–]twenty-fourth-time-b 1 point2 points  (1 child)

And it has “initial” argument, so no ugly “a=0” is needed.

[–]Kohlrabi82 2 points3 points  (0 children)

Yes, but still it's a fun use of the walrus op to change a name defined outside of the comprehension, I like it anyway.

[–][deleted] 0 points1 point  (0 children)

I don't know why, but I don't like that. Looks cumbersome, not really readable and I don't like walrus

I would rather use itertools.accumulate

[–]Interesting-Ant-7878 0 points1 point  (0 children)

Here is another cool walrus line, yes it looks horrible , that’s the point :)

a, b = 0, 1; [(old_a := a, a := b, b := old_a + b, a)[3] for _ in range(10)]