27 comments

[ 4.6 ms ] story [ 59.1 ms ] thread
At least it introduces a new operator, to avoid the classic C mistake of typing "=" when you meant "==", and various ugly workarounds like Yoda conditions.

This would be a huge boon for many list/dict/set comprehensions, as currently there's no way to filter on the result of a function call in the same comprehension (map + filter in one):

  results = [b for b in input_data if (b := f(a))]
I think it's slightly unpythonic as it has the potential to be abused and make debugging harder (as noted in the post/email), but otherwise I can't think of a reason not to do it.
That's a better use case, but this just seems like something that's adding complexity to the language for little gain. Writing a generator to do the more complex thing is probably a much better (and more readable) alternative, if a list comprehension isn't cutting it.
> `results = [b for b in input_data...`

Did you mean `[b for a in...`?

Assuming so, there’s [result for a in input_data for result in [f(a)] if result] if you’ve just gotta make it a comprehension.
This case could also be addressed by something more like PEP 3150 without the nasty potential for leaking the scope of an assignment beyond that statement in a non-obvious way.

https://www.python.org/dev/peps/pep-3150/

It's an open question whether that's more readable than the already legal

    results = [b for b in (f(a) for a in input_data) if b]
>At least it introduces a new operator, to avoid the classic C mistake of typing "=" when you meant "==", and various ugly workarounds like Yoda conditions.

Well, = and == in C are two different operators as well.

The problem is more allowing non-boolean comparisons

As a long-time Python user, this is one of the worst proposals I've seen.

Yes, it has a potential for being useful.

But its usefulness, unlike context managers and async, is very limited, implied a substantial cognitive overhead by introducing a new operator, and has a very significant potential for abuse.

One of the nice things about Python is that it is highly succing while disallowing the sort of expressions that are too information-dense to be easily understood, which has been a critique of mine in other languages of similar use cases (Clojure, Haskell, I'm looking at you).

Succinctness is good if it allows expressing ideas in a way that maximize comprehensibility and go straight to the point.

But truth is, nobody's missing out on serious functionality by not being able to do an assignment on the same line of code as a conditional. It can be very slightly annoying, possibly. But I look at the examples and I'm really not convinced that this feature is so orthogonal and useful as to merit inclusion.

It feels like accepted PEPs are slowly coming under less scrutiny and disregarding the idea of feature orthogonality and low overhead.

It isn't an accepted PEP, just a draft.
Whilst I personally prefer succinct code, the proposal looks to be unpythonic. Why is this any better than ‘—i’? Arguably the same thing could be said for list & map comprehension.
>It feels like accepted PEPs are slowly coming under less scrutiny and disregarding the idea of feature orthogonality and low overhead.

I have been noticing this long before. For me it was with the pep that dealt with automatic string interpolation, i think it was 498..

What I love about Python is that it has a limited set of "symbols" I had to learn. I would have for new cryptic combinations of characters to arise with some kind of meaning.

> The LONG version looks like your expressiveness is limited by the computer. It's like having to use simple words when you talk to a child, because a child is unable to understand more subtle and advanced sentences.

Fantastic! Easy to understand code is what makes Python so great.

Easy to understand code is what makes Python so great.

"Easy to understand" doesn't mean "every individual statement should be as simple as possible". Otherwise we'd be using assembly for everything.

I think we agree? I want readable, not simple/small.
Wow. I would love to see this become real. There are so many cases where I want to be able to use assignment as an expression like in lisp and it is simply not possible in python because of how locals works. This would (hopefully?) finally make it possible to assign names dynamically in python which is a feature that is sorely missing and leads to enormous amounts of code duplication where sometimes you have to write the same variable 3 times when you should only have to write it twice (the if statement example is exactly this). f-strings solved some of those issues, this looks like could solve some of the others.
I find the short example a strange choice. Sure, you can build a crazy expression which is hard to process / read / debug. But the change also enables this, which solves most problems raised and makes reading easier:

    if diff := x - x_base:
      if (g := gcd(diff, n)) > 1:
        return g
Or even this, depending on preference:

    if diff := x - x_base:
      g = gcd(diff, n)
      if g > 1:
        return g
This proposal looks on the surface to be useful but the more I think about it, the feature look like it would be awful for those of us who try to write side-effect-free code whenever possible. The assignments made here leak their references to all following statements, making it much harder to track the actual ramifications of any of these assignments.

I'd say this is in stark contrast to PEP 3150 which tries to solve similar problems but does so by introducing functional let-style statement-local assignments, retaining an amount of "encapsulation" of expressions and their sub-expressions.

> You can see it as a limitation of pdb, but many tools only have the granularity of whole line

As somebody who likes to write quite "functional" code, I do see this as a significant limitation. But it's one that I'd really like to see addressed rather than used to restrict our ability to express our intentions in succinct ways.

> write code for babies!

I strongly disagree with this notion. Professional developers are supposed to be professionals, as in, people whose (paid!) job is to write code full-time. It's a discouraging trend to be principally structuring your engineering project around the abilities of (full-time!) coders who can often had rings run around them by amateurs. Code written "for babies" (presumably omitting language features because some may not know them) tends to turn into a long winded mess all too quickly.

How are babies ever supposed to learn to be anything else if all they ever see is baby code?

> I'm trying to write a single instruction per line whenever possible

I'm glad he phrased it like this, because I find reading code written like this uncannily like reading assembly.

I'm not particularly sold on this proposal, but the examples in the OP seem like poor counterarguments; there are a lot of ways to write incomprehensible python. (Nested list comprehensions anyone?)

And it's already possible to write one-liners that do too many things; I'm not convinced that this proposal would make that worse.

Best to consider how this feature would actually be used, and make a judgement as to whether the value outweighs the cost of making the language more complicated and harder to learn.

This proposal does have some benefits - this is the best use-case I can think of:

Instead of

  response = do_thing()
  while response != 200:
    handle_error(response)
    response = do_thing()
  
(Which in many other languages would be a do-while)

Instead we could write:

  while (response := do_thing()) != 200:
    handle_error(response)
That doesn't seem like a big improvement though...
Looks like a major improvement in readability to me...
It does make that case more readable, yes -- but is it worth making the language a bit harder to learn for new developers?

Two assignment operators instead of one doesn't seem that hard to wrap my head around, but Python is used widely in education as well, and we should also pay heed to the lessons of C++ - the road to incomprehensible languages is paved with good-intentioned syntax.

As a long time Python programmer and even longer time Wolfram Lang/Mathematica programmer, I just look at this and think “yea, that’s exactly how I thought assignment worked When I started learning Python”

I mean what else than the assigned value would you expect an assignment to return? Naturally Python assignment is a special concept, but in Mathematica assignment is just a function. So it seems more natural in Mathematica. I wouldn’t mind this, however it does seem like Python deliberately tries to be less functional, hiding away map/apply and such elements and recommending lay comprehensions, so it might just not fit with Python as it is now.

I think this has been possible in PHP since forever and that community treats it as bad practise. Let's not repeat PHP's mistake 20 years later...
Perhaps the 20-year mistake of PHP is treating it as a bad practice?

This has been possible in functional and "expression" languages since forever, and it's considered a very good practice.

> This has been possible in functional and "expression" languages since forever, and it's considered a very good practice.

Really? Can you show an example?

Yes. sadly, I think this is spot on. I started noticing this trend with PEP 498 (Php like string interpolation). One can only hope it won't ever become so bad...
python variables are stored in locals()(read only dict)

we have "{NAME : EXPR}" for dict

just do "(NAME : EXPR)" with parenthesis

within its scope, list comp can be

<code>results = [b for a in data if (b: f(a))]</code>

perhaps even with c++ range based for the win

<code>results = [win for (the: data) if (win: f(the))]</code>