All in all the debate has been heated and long, but it has been decided that the python community will use it intelligently and rarely, but that when it matters, it can help a lot.
I'm against this feature, while I was pro f-string. However, I'm not too worried about missuse and cultural shift because I've seen 15 years of this show going on and I'm confident on it's going to be indeed tagged as "risky, use it knowing the cost" by everybody by the time 3.8 gets mainstream.
They are most of the time a fantastic indicator of the cognitive load a feature will add in prod. Because of course a feature doesn't exist in a vacuum, it's always in a more complex context. So what's easy to understand for a student will be alright for a pro in the complexity of real life engineering. And I found the opposite to hold quite often as well.
I haven't tried the walrus on them yet, but I'm pretty sure of the result.
There are already so many complicated semantics about mutability, iteration, bytes/strings, scoping, et al. And yet somehow a tiny piece of syntax that finally lets us stop writing "while true/break" is the big pain point?
That is fine if you want to optimize language for "fresh students". That is not representative how brain process stuff after getting even some experience.
m = re.match(...)
if m:
... do something ...
is verbose, but quite readable. Given that it's the way things have been done since forever, it's also unsurprising. if m := re.match(...):
... do something ...
Without knowing what the walrus operator is, it is not entirely clear what is going on here. := is only syntactic sugar, which is not what Python has ever been about. if m := re.match(...); m {
... do something ...
}
Still not as readable as splitting it over multiple lines but quite a lot better than Python's syntax IMO especially once you learn how the if statement works in Go. with open('file') as f:
... do something ...
I don't know why that didn't come out on top in the debate. if re.match(...) as m:
... do something ...In the link above, the "as" keyword would work with (very close to) all of those lines and arguably more readable.
x = function_that_might_return_none()
if x: do_stuff
The walrus simultaneously names the value being tested so you can refer to it within the condition; it's sort of the inverse of Perl code using $_. So instead of
if (do_something()) {
act_on($_);
}
you have if placeholder := do_something():
act_on(placeholder)
But when reading aloud, however you'd read the perl will flow as more natural english. "If the string contains z, do something with it".If you really want to read the Python as it's written, it corresponds to the second of these sentences:
- If the substring from 3 to 5 is "fg", crash.
- If variable_name, the substring from 3 to 5, is "fg", crash.
Once way to test if this works is to take the code, read it aloud, and then use the read-aloud version to rewrite the code. If you don't have a high degree of certainty that you end up with the same code, something has failed along the way.
In this case, if I take "if x:= y()" and read it aloud as "if y", I think the vast majority of people would translate that to code as "if y():", which isn't the same thing.
1. You read more than one line of code.
2. Executing the code in the conditional more than once doesn't matter.
If you meet those two assumptions, then the reading I suggested will transform this
if x := y():
act_on(x)
into this if y():
act_on(y())
which is, in fact, the same thing.And if you're referring to this statement from your original comment:
> If variable_name, the substring from 3 to 5, is "fg", crash.
I don't find this to be a clear statement at all. If I read this aloud to any of my programming students, I doubt any of them would be able to decipher it into any code, let alone the code string which you've suggested.
A couple of reasons:
- The walrus eliminates a line of code in the very common scenario where you would prefer not to recalculate (or retype) y().
- The walrus makes it easy to avoid recalculating y() in the less common scenario where you need to avoid doing that.
> I don't find this to be a clear statement at all.
Nonetheless, it is the normal English syntax used to name something and then immediately define the meaning of that name. If you want to map the Python structure to an equivalent English structure, that is the equivalent English structure. ("Thomas Jefferson, the third president, was a man about whom much can be said.") If you want to map the Python code to an English statement of what the code does, use the reading I first suggested, "if y(), do something with it". If you want to dictate Python code to an English speaker, use the reading "if x colon-equals y()".
So let me ask you: is the problem you'd like to solve "I want to understand what this code does", is it "I like thinking about English grammar", or is it "I'm too busy to type my own code; that's what my secretary is for"?
The problem that has already been solved by every version <3.8 of Python, and that I would hate to see become un-solved by Python in the future, is that Python's greatest attribute, by far, is that it has always stuck to a code of being "pythonic", increasing accessibility, readability, and teachability to wide audiences. A hugely significant reason for Python's incredible rise in popularity and its use today is specifically because of it's readability. As much as it gets meme'd about, the fact that Python pseudocode is so close to real Python code is an enormous boon for the language.
I teach programming at a university level, and Python is the go-to, default language to teach programming. Dictating code so that it can be discussed in a classroom setting is very important, and as I mentioned before, your suggestion for reading it aloud just wouldn't cut it. Python is also the go-to, default language for programming-adjacent fields like data science, a lot of statistics, and every other non-programming-but-still-IT field. And again, this is because the people in these fields love the fact that, even with zero previous programming experience, they can look at or hear a piece of code and almost immediately understand what it is doing.
Python's strict adherence to being "pythonic" is hugely responsible for an entire generation of programmers, and hopefully will continue to be pythonic enough to continue lowering the barriers of entry to future programmers. I get that many seasoned developers are adopting an "well I got mine" attitude and don't care if future developers have a harder time learning the trade, but I personally find that to be very selfish, and I would hate to see future generations of programmers suffer just because the current generation apparently can't be arsed to do something like write one single, short extra line of code every now and then.
Every now and then? If you look at the example in the post, you'll see it saving one line of code per branch of the if-elif ladder.
Python code is characteristically tall, and this saves a lot of lines, and it saves them all in exactly the same way.
Yes, every now and then. The example in this post is an edge case. And even if it wasn't, the walrus operator saved a grand total of three (3!) keystrokes/characters per conditional in the example. "saves a lot of lines" is hyperbole. If the goal of this was saving programmer time or reducing the amount of code, the walrus operator should have been one of the absolute last things in Python to change.
Even just within this HN thread, even the staunchest proponents of this change are admitting that it is only going to be used sparingly, and at best saves a handful of lines of code per project.
If you're seriously telling me that saving a measly three keystrokes is more important to you than maintaining the pythonic philosophy that has made Python successful for decades, I can say nothing else other than that I strongly encourage you to reevaluate your priorities.
edit: I actually did the math wrong. It's only two (2!) keystrokes saved per conditional.
Even if y isn't mutating itself, it may be calling from a database updated from another thread.
You end up storing the value. The walrus simplifies the code.
For what it's worth, "x = y()" is one of the harder things for new programmers to translate to English in the first place -- it reads most naturally as "x equals y," but leads to better intuitions as "x gets the value of y". I think that's what makes this clunky to verbalize, rather than the "if truthy" bit.
> For what it's worth, "x = y()" is one of the harder things for new programmers to translate to English in the first place
Right... so why have we added more complexity to something known to be very complicated?
to quote the PEP:
reductor = dispatch_table.get(cls)
if reductor:
rv = reductor(x)
else:
reductor = getattr(x, "__reduce_ex__", None)
if reductor:
rv = reductor(4)
else:
reductor = getattr(x, "__reduce__", None)
if reductor:
rv = reductor()
else:
raise Error(
"un(deep)copyable object of type %s" % cls)
becomes: if reductor := dispatch_table.get(cls):
rv = reductor(x)
elif reductor := getattr(x, "__reduce_ex__", None):
rv = reductor(4)
elif reductor := getattr(x, "__reduce__", None):
rv = reductor()
else:
raise Error("un(deep)copyable object of type %s" % cls)No, “if <expression>” expands to “if <expression> has a truthy value”.
“<var> := <expression>” is itself an expression, which can be best (IMO) read in English as “<var> (which is <expression>)”
“... x := foo ...” is read “... x, which is foo, ...”
I've had to use a workaround for that every time I've tested a regular expression match that I wanted to process for example. Also problematic in comprehensions...
I should know, I've worked with Python for 22 years...
This feature is kind of a symbol, the first real decision of the transition between the bdfl and the next era.
I'm not worried about it, but yes, it was really against python core principles.
The zen of Python is not a binding constitution. It does not mean nothing can be added if there is some way to do it already, especially if that way improves things. It’s no more “going against the principles” than f-strings where, and they turned out just great.
So one might argue that a principle of python is that the language is dictated by how people read and write rather than the other way around... it's pretty hard to say what principles are "core" when they all conflict and you have to weigh various tradeoffs.
[1]: https://www.python.org/dev/peps/pep-0572/#the-importance-of-...
Regarding that it took 25 years, the normal Python syntax has been enormously successful. People don't tend to look for problems in things that work.
Guido also rejected several ideas that would totally fit with Python in those decades. There are lots of concerns (including implementation ones), not just what fits with some hypothetical "Zen", which was never meant as a contract anyway.
Besides Guido finally agreed to it, and even quit because of it.
If Python was to be kept "simple" at all costs, it would have added 20 other things, from operator overloading to yield from over those decades, some far more complex, and non-local than the operator change.
You can browbeat people all you like but we are not forced to work with any particular language and if it diverges away from what we liked we will just switch away.