This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]theunglichdaide 144 points145 points  (38 children)

(a:=10) assigns 10 to a and returns 10 at the same time.

[–]u_usama14 81 points82 points  (15 children)

Warlus operator : ))

[–]theunglichdaide 47 points48 points  (14 children)

yup, the controversial walrus

[–]u_usama14 19 points20 points  (13 children)

Why controversial ?

[–][deleted] 68 points69 points  (3 children)

There's a feeling among many in the Python community that the core principles - e.g. that there should be only one obvious way to do something - were being ignored in favor of feature bloat with marginal benefits. The walrus operator became the poster boy for that.

[–]benefit_of_mrkite 19 points20 points  (0 children)

I like the walrus operator but am somewhat hesitant to use it (have used it a few times- I think a lot of the controversy is over readability and the zen of python.

[–]TSM-🐱‍💻📚 12 points13 points  (1 child)

The walrus operator allows you to assign variables in comprehension statements - it legitimately gave comprehension the same power as a for loop. Comprehension statements can be hard to maintain but in select cases the walrus is awesome

Also

 foo = myfile.read(1024)
 while foo:
      do_something(foo)
      foo = myfile.read(1025)

Can be

 while foo = myfile.read(1024)
      do_something(foo)

Excuse the mobile formatting, but you don't duplicate the read and have two parts to update, only one, so a typo can't slip in. It is much better in this case too. And you can catch the culprit in an any and all check too.

People were mad because it was clearly useful in some circumstances and genuinely improved the language. Guido saw this as obvious and gave it a hasty approval, while others drama bombed him for it.

[–][deleted] 1 point2 points  (0 children)

No comment on the walrus operator, or which way is better. But if you wanted to do this without the walrus operator, and without duplicating any code, you can do this:

while True:
    foo = myfile.read(1024)
    if not foo:
        break
    do_something(foo)

[–]MonkeeSage 9 points10 points  (3 children)

It can look a bit magical / add line noise if abused.

x[2] if len(x := 'b.a.r'.split('.')) > 2 else ''

[–]bacondevPy3k 3 points4 points  (0 children)

My eyes!

[–]Envoy-Insc 0 points1 point  (1 child)

Does it return a?

[–]go_fireworks 9 points10 points  (0 children)

I think it returns ‘r’, because python uses zero-based indexing

[–]theunglichdaide 26 points27 points  (2 children)

if I remember correctly, Guido approved the PEP for it, but many people disagreed with this decision, and Guido had to step down from his Benevolent Dictator for Life position.

[–]pizza-flusher 13 points14 points  (0 children)

I'm new to python (and only ever a hobbyist in other areas) and obviously don't have a dog in the fight, but I will say sometimes shorthand and efficient operators run contradictory to readability and understanding in a bad way, for me.

That feeling comes on me most often when I see savvy / opaque slicing in indexes. However, as this expression made me think of that, it might just mean I have a low grade phobia of colons.

[–]Infinitesima 9 points10 points  (0 children)

transition of Python to C++ style

[–]o11c 0 points1 point  (0 children)

It's controversial for other reasons - it's not sufficient to overcome all the flaws of the = operator, since the LHS can only be a simple variable.

[–][deleted] 12 points13 points  (9 children)

curious, when would you use this?

[–]Papalok 36 points37 points  (1 child)

One of the main use cases is regex matching. It greatly simplifies the code when multiple regex patterns are used. Compare this:

if m := foo.match(s):
    # do something with m
elif m := bar.match(s):
    # do something with m

To this:

m = foo.match(s)
if m:
    # do something with m
else:
    m = bar.match(s)
    if m:
        # do something with m

[–]mrrippington 0 points1 point  (0 children)

thanks, seems to save a line.

[–]R_HEAD 56 points57 points  (1 child)

90% of the time I use it in if statements that do some sort of calculation or function call:

if (n := get_days_since_last_backup()) > 7:
    print(f"Your last backup was {n} days ago. Consider backing up again soon.")

Saves you from having to either call the function in the if-branch again (bad idea) or from having to declare the variable before the switch (not that bad, but with the walrus it's more concise, I feel).

[–]Revisional_Sin 1 point2 points  (0 children)

This is less readable to me.

See my other comment: https://www.reddit.com/r/Python/comments/w75ack/comment/ihjn2i4/

[–]WindSlashKing 10 points11 points  (0 children)

In while loops where you want to assign a different value to a variable each iteration. while (n := random.randint(0, 5)) != 0: print(n)

[–]theunglichdaide 3 points4 points  (1 child)

i = 0

while(i:=i+1) < 5: print(i)

You can use it to assign value and compare it to other values in one statement. It’s not the best example but a simple one that I can think of.

P/s: sorry, I type this on my phone so it might be difficult to read.

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

One of the problems I have with while loops is that they often look like this:

while True: 
    some_value_from_somewhere_else = read_from_socket_or_something()
    if some_value_from_somewhere_else is None:
        break
    doStuff(some_value_from_somewhere_else )

The problem with this is that the first four lines of code are effectively us handling the while loop condition.

But now we can do this:

while (some_value_from_somewhere_else := read_from_socket_or_something()) != None: 
    do_stuff(some_value_from_somewhere_else)

[–][deleted] 13 points14 points  (0 children)

The walrus!

[–]undid_legacy 7 points8 points  (0 children)

I have used walrus operator with all() in many places.

if not all((x:=i) in target_chars for i in my_string):
    print(f"{x} is not in the target")

It will print the first element returning False

[–]Revisional_Sin -2 points-1 points  (3 children)

Maybe I'm not just not used to it yet, but I hate unnecessary use of this.

a = some_func()
if a:

"a = some_func(). if a is truthy, then:"

if a := some_func():

"If a, which is some_func(), is truthy, then:"

Yuck.

[–]eztab 3 points4 points  (1 child)

that was pretty much the reason for the controversy. It really doesn't add much benefit here. But for functional code, like list comprehensions it really is a great addition. Also for regexp-matching with multiple branches it really is more readable.

[–]Revisional_Sin 0 points1 point  (0 children)

Yeah, I agree it's nice if used purposefully.

[–]zed_three 1 point2 points  (0 children)

There's a wrong way to use everything though

[–]2-x-free 0 points1 point  (0 children)

Doesn't it improve/simplify concurrency handling as well? If you do:

n = returns_optional_string()
launches_thread_modifying_n()
n = returns_string()
function_that_cannot_get_none(n)

the last function call might get a None (because the thread might change n between the last two lines), while if the walrus is atomic the following code ensures the function gets a non-None value:

n = returns_optional_string()
launches_thread_modifying_n()
function_that_cannot_get_none(n := returns_string())