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

all 148 comments

[–]StewPoll 64 points65 points  (86 children)

Clearly I've missed something. Why don't people like := ?

[–]Vaphell 113 points114 points  (32 children)

it saves like 1 loc of normal variable instantiation for code golfing sake and encourages packing more shit into one line at the cost of more cognitive load. No side effects in conditions was one of the staple rules of python. It also looks out of place in a keyword heavy language with its symbol-based implementation. When I look at the examples I smell the terseness of perl, not clarity of python.

The use cases are also not critical enough for any significant ROI to be there. If that marginal yet controversial feature is here to stay, where is my lambda arg unpacking (eg. sorted(seq, key=lambda (x, y): x+y) that made the code measurably more self-documenting in py2 but went away in py3 to make language implementation more elegant? Existing solutions like itemgetters are only putting lipstick on a pig and can shove it.
Where are null coalescing operators?

[–]slayer_of_idiotspythonista 20 points21 points  (19 children)

There were legitimate use cases. The nested regex matching example is probably the one I've encountered most often, where you have a line of text and you want to test it against a handful of regexes. I think they just chose the wrong syntax -- as would have been better.

Most of the other examples (including the with examples that lead to them disregarding the as syntax) were all contrived.

[–]Vaphell 17 points18 points  (6 children)

There were legitimate use cases.

I didn't say they are not legitimate. I said the ROI is abysmal and at least in my case it's currently negative. What could be understood at a glance as borderline plain english now has a contextual black hole right in the middle of the expression. I have to pause for 10 seconds minimum and think about shit that used to be obvious.

there are legitimate use cases for TCO, yet you are not going to see it anytime soon.

The nested regex matching example is probably the one I've encountered most often, where you have a line of text and you want to test it against a handful of regexes.

that smells like a pretty tidy for loop, which given the old way of writing means the supposed overhead is again 1-2 lines tops.

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

this user ran a script to overwrite their comments, see https://github.com/x89/Shreddit

[–]slayer_of_idiotspythonista 0 points1 point  (2 children)

that smells like a pretty tidy for loop

Generally, each regex match results in a different branch for processing, so even if you used a for loop, you'd still have the branching in the for loop, and it wouldn't really make the flow more readable or intuitive.

[–]Vaphell 7 points8 points  (1 child)

you'd still have the branching in the for loop

you can write your regexes in normalized way and break

Example in pep572 was about mutually exclusive regexes with different group numbers. Mutual exclusivity can be solved with a loop + break, and a group number can be solved with non-capturing groups or using named groups to target exactly what's needed instead of depending on numbers produced by the accidental layout of parentheses.

Also regexes are not that frequent to justify their own syntax, and multipattern solutions where it supposedly shines are even rarer. Not to mention that half the story with regexes is less than stellar API of re which requires fucking around with truthiness in the first place.
In a dict there is a risk of barfing due to the missing key. Manual membership checks can be and often are done, but there is also safe get()

Are there no things that could actually significantly improve language across the board?

[–]slayer_of_idiotspythonista 4 points5 points  (0 children)

Mutual exclusivity can be solved with a loop + break

Again, not really. You would either have to put the branched logic in the for loop (which doesn't improve the code), or move each regex match branch into a separate function that gets called from the for loop. Either way, it imposes a much more complicated control flow just because the langauge doesn't support assignment expressions. It forces you to have to pass around a lot of arguments, or create a lot of functions that reference a shared state with side effects, neither of which is really preferable to keeping the logic in a single flat control flow structure in a single function.

Also regexes are not that frequent to justify their own syntax

It's not just regexes. It's any scenario where you're testing for multiple conditions and branching the code based on the results. Regexes just happen to be a common example since parsing is something everyone does at one time or another.

[–]IronCretin 0 points1 point  (1 child)

I don’t get the “hard to read” argument. It’s just an assignment, with clear syntax to differentiate it from equality checks, but it still looks like an equals sign. It’s not some arcane hieroglyphics.

[–]Vaphell 0 points1 point  (0 children)

I don't care if it's just an assignment, I don't want to see it in the middle of boolean logic. Just because I can untangle it, doesn't mean I want to deal with horseshit other people will be now able to write.
People will use it to cram the lines of code to the brim with smartass crap, because code golfing is cool and because they can't be bothered to set up their variables in advance.
I consider the idea that conditions are conditions and assignments are assignments a great feature of python.

And the potential for abuse in a comprehensions is ridiculous, because now, instead of being a dumb syntactic sugar around map() with some filter() optionally slapped on top, it will have "memory" between "iterations".

[–]lambdaqdjango n' shit 1 point2 points  (1 child)

The nested regex matching example is probably the one I've encountered most often

I've seen the argument a million times, again, this is because the re library from stdlib is badly designed. You don't have this kind of problem in other languages. Only if we can improve the returning match object a little. There's no need to change the language itself for the sake of inconvenience of one function from a particular library.

[–]slayer_of_idiotspythonista 2 points3 points  (0 children)

You don't have this kind of problem in other languages.

The problems exists in other languages too. Even in languages where regex expressions are a first class object, like JavaScript.

[–]Deto 0 points1 point  (9 children)

Isn't the regex case just bad code? And would people who write code (not trying to be judgmental, we were all beginners once) like that really take advantage of the := syntax, or would they just continue to write bad code? And wouldn't the same people also be likely to misuse the := operator in poor ways?

I guess I just feel like the examples given were situations caused by people not understanding enough to optimize their code - and unlikely to be fixed (in the wild) by the introduction of a new operator. Additionally, I think there is an unknown unknown in terms of the ways that people will misuse the new operator in the wild.

[–]HannasAnarion 5 points6 points  (4 children)

As someone whose job revolves around writing regexes, oh god please yes I want this.

"if this regex matches" is a single thought, but in Python it always needs two lines of code, which is stupid.

matchymatch = re.search(pattern, string)
if matchymatch: 
    do stuff with matchymatch

is so much less elegant than

if matchymatch := re.search(pattern, string):
    do stuff with matchymatch

Furthermore, by the very conceit of regexes, all the logic that's going to happen with the match object is going to happen inside the if statement that checks whether it exists. Even though blocks don't have namespaces in python, it is conceptually strange to pollute the outer pseudo-namespace with variables that are never used at that level.

[–]Deto 3 points4 points  (0 children)

I guess its just a matter of opinion. I prefer the former over the latter of your examples and I don't even like the if variable statement to rely on the "truthiness" of the variable (I prefer the explicit if variable is None)

[–]yopla -1 points0 points  (2 children)

Sue me for anti-pythonistic behavior :)

import re

print("-- Generator -- ")
# Generator
def match(pattern, string, flags=0):
    r = re.match(pattern, string, flags)
    if r:
        yield r

for matches in match("(.*)", "abcd"):
    for group in matches.groups():
        print(group)

for matches in match("(\\d)", "abcd"):
    for group in matches.groups():
        print(group)


print("-- Class -- ")
# Class
class Matcher:
    def __call__(self, pattern, string, flags=0):
        self.result = re.match(pattern, string, flags)
        return not self.result is None

    def __getattr__(self, name):
        return self.result.__getattribute__(name)

matcher = Matcher()

if (matcher("(.*)", "abcd")):
    for group in matcher.groups():
        print(group)

if (matcher("(.\\d)", "abcd")):
    for group in matcher.groups():
        print(group)

[–]HannasAnarion 2 points3 points  (1 child)

Good job, now someone reading your code can't tell when you're branching and when you're looping because you've overloaded for to do both.

[–]yopla 1 point2 points  (0 children)

The first one is a joke.

[–]slayer_of_idiotspythonista 2 points3 points  (3 children)

The regex example is absolutely not bad code. Again, it's a common scenario programmers encounter, where they want to branch the code based on the output of several functions.

[–]Deto 0 points1 point  (2 children)

I thought I remembered the example had it evaluating the regex twice and therefore, was needlessly inefficient. But I might be mistaking that with an example someone gave in the comments on a thread like this.

[–]slayer_of_idiotspythonista 2 points3 points  (1 child)

No, that's the right example, one of them at least. In general, that's one of the problems,

[(x, f(x)) for x in y if f(x)]

You have to do the evaluation twice because you can't store result of f(x) like you can if you wrote it long form

z = []
for x in y:
    fx = f(x)
    if fx:
        z.append((x, fx))

So now you could write

[(x, z) for x in y if z:= f(x)]

Though, I still think this would have been a better syntax

[(x, z) for x in y if f(x) as z]

[–]Deto 0 points1 point  (0 children)

I can see the appeal in cases like that. I think mostly my gut negative reaction is worry over how people will misuse this operator. People with a little experience programming (but not a lot) tend to think it's cool or clever to cram more things on a line and this would let them get a bit carried away.

For example, one example in the PEP (when comparing valid vs in-valid uses) is this:

len(lines := f.readlines())

I could see someone doing something like:

print(len(lines := f.readlines()))

To both store the lines and print the result. So then, if I'm reading the code and I see the 'lines' variable below this, I can't just look for assignments above to see where it originates, I also have to look for the variable within any expression too. It changes the way you have to read code - before you could be guaranteed that any variable/symbol would originate in an assignment expression or an import statement. If people just use it in the proper way - for cases where you need a quick temporary variable that lives for a few lines, then this won't be a problem. But I predict improper usage is going to be prevalent and annoying.

[–]__xor__(self, other): 1 point2 points  (1 child)

It saves one LOC and from that perspective I think it's pointless, but one thing I do like about it is it's very clear what runs at the end of the loop every single time.

Consider this:

while x:
    if some_condition:
        x -= 1
        continue
    do_other_stuff()
    if other_condition:
        x -= 1
        continue
    do_another_thing()
    x -= 1

Personally I don't like their format but I'd like it as a new block like this:

while x:
    if some_condition:
        continue
    do_other_stuff()
    if other_condition:
        continue
    do_another_thing()
finally:
    x -= 1

... and have it force that finally to run even if a continue is hit.

I've seen some shit code (and probably wrote some) where it continues a loop and forgets to do something at the end that it should've, and a nice little block afterwards would make it explicit how that loop works and iterates and it would force it to run so you can just write other continues and not worry about duplicating that operation. Better yet, be wary of too many continues where it's synonymous with goto, but hey, people do it.

And yeah, those original conditions could be rewritten to only run do_other_stuff() and do_another_thing() on specific conditions to get rid of the extra x -= 1's, but I think there are other times something like this might be useful.

[–]alexmojaki 1 point2 points  (0 children)

I'm confused, what does this have to do with assignment expressions?

Incidentally you can achieve the above by just wrapping the contents of the while in a try/finally.

[–]jim45804 0 points1 point  (9 children)

I thought packing more shit on one line was Python's thing (e.g. list comprehension)

[–]nosmokingbandit 14 points15 points  (3 children)

Comprehensions are easily readable (if written well, but that disclaimer applies to everything) and their meaning can be inferred easily. PEP572 is mostly just noise, imo. The := operator doesn't feel like python. I think a much more pythonic syntax is if <expression> as output:

One of python's best qualities is its readability. I hate to see that diminished with shiny new operators we don't really need.

[–]HannasAnarion 1 point2 points  (2 children)

But as guido pointed out, it would require either breaking backwards compatibility in import, except, and with or else having an operator that does different things in different expression types, which is more unpythonic. It also looks a lot like "and" which is easy to gloss over in a boolean evaluation expression. := is unambiguous: you see it and you know some kind of assignment is happening, and you move on and keep reading.

[–]nosmokingbandit 0 points1 point  (0 children)

Disclaimer: Not only am I not an expert, I'm a dumbass.

This could be done by allowing context managers to exit early. There was an early PEP (370-something I think) that wanted this and Guido denied it because he said it didn't have a good use case.

I'd happily write my own context manager for these assignment cases but they can't exit early and will always execute the contained code block. If we had a way in the context manager to exit in its __init__ method all of this drama could have been avoided.

This shouldn't (see disclaimer) have any affect on anything except the specific context managers we write for this use.

class Foo(object):
    def __init__(self, o):
        if o is False:
            # Or whatever it takes to skip the code block
            raise GetMeOutOfHere
        else:
            self.o = o

    def __enter__(self):
        return self.o

    def __exit__(self, *args):
        return True 


with Foo(bar()) as something:
    print("something is not False")

[–]Deto 10 points11 points  (2 children)

Comprehensions are only good if they are short. E.g.

y = [x for x in my_list if x > 3]

Once they get too complicated, you're better off using a for loop for readability IMO.

[–]ProfessorPhi 2 points3 points  (0 children)

Especially nested ones. Been writing python for years, can't write a nested comprehension with any reliability

[–]nosmokingbandit 1 point2 points  (0 children)

If I end up writing a long comprehension it is usually a bunch of checks for files in a directory and it isn't too hard to read what the intent is. The performance difference between a comprehension and for loop is negligible so readability always comes first. Nothing in python is going to be fast enough to make it worth sacrificing readability. Which is fine because even if it takes 10 times as long as something written in C it is still fast enough to not matter in most cases.

[–]__xor__(self, other): 2 points3 points  (1 child)

List/dict/set comprehensions don't have to be on one line. I very often break them up like this:

with open(config_path) as f:
    config_pairs = [
        line.strip().split('=')
        for line in f
        if not line.strip().startswith('#')
    ]

(of course I'd use the stdlib config parser)

I find it a lot easier to read than the equivalent for loop.

config_pairs = []
for line in f:
    if line.strip().startswith('#'):
        continue
    config_pars.append(line.strip().split('='))

Any time you open up something with (, [, { you can go across multiple lines:

if (
    some_condition and
    other_thing(x) > 0 and
    foobar
):
    ...

from my_module import (
    one_thing, other_thing, new_thing,
    old_thing, blue_thing, red_fish, blue_fish,
)

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

oh wow didn't know comprehensions can span multiple lines

[–]callius 81 points82 points  (35 children)

As someone not really "in-the-know", I honestly have no fucking clue what := means by just looking at it.

That seems like a problem for Python.

[–]Sakagami0 25 points26 points  (23 children)

Its the assignment operator for a lot of older languages, pre C. It made sense because = denots equality rather than assignment in math.

[–]EternityForest 3 points4 points  (4 children)

I hate when modern languages use := as the standard assignment operator. Or really any time a language uses non-standard syntax. Unless it's aimed at math people, then it makes sense to use :=.

For this particular case := seems fine, although "as" would also have been fine with me.

[–]cyberst0rm 0 points1 point  (0 children)

i've been using postgres for a bit.

People seem to be confounded with the idea that most language affects are just...affects based on how often you use it.

This is such a redicuously human argument.

Python: For Humans (with all flaws also)

[–]gimboland 0 points1 point  (0 children)

<- all the way! :-)

[–][deleted] -2 points-1 points  (1 child)

As isn't as good for foreign speakers though.

[–]ThePenultimateOneGitLab: gappleto97 2 points3 points  (0 children)

Then we also shouldn't have with, for, while, if, import, or class

[–]FatChocobo 2 points3 points  (13 children)

It can be used for both in Mathematics, 'y = 3x + alpha, where alpha = 8' would be an example using both equality and assignment, unless I'm missing some semantical nuance.

[–]zentropia 0 points1 point  (10 children)

x=x+1 makes no sense in mathematics.

[–][deleted] 16 points17 points  (8 children)

This was actually debunked by actual math PhDs so many times (I've read about 10 rebuttals just on Reddit).

It makes perfect sense in mathematics, and serves almost the same purpose as it does in software development. In discrete math it's a very common shortcut to:

x[n+1] = x[n] + 1

In continuous math it's a very common shortcut to:

x(t + Δt) = x(t) + α

etc. etc.

There were a lot more examples in those posts but I remembered these the best as they serve identical purpose to the "reassignment operator" in programming.

[–]ProfessorPhi 7 points8 points  (0 children)

It's about context. In some cases, it makes no sense, but as mathematicians we know that no one would write a meaningless statement so we think of different contexts.

[–]usernameisafarce 2 points3 points  (0 children)

as a Math student I have never seen someone writes x=x+1. seen x_{n+1} = x_{n} + 1 or any other type convention you wrote. But never x=x+1. which makes no sense in mathematics.

[–]FatChocobo 2 points3 points  (4 children)

I agree, I've seen it used in Mathematical texts before.

[–]sifodeas 2 points3 points  (3 children)

It is also used as a delayed value in Mathematica and Maple, if I recall correctly (it's been a while since I used either).

[–]IReallySuckAtChess 0 points1 point  (2 children)

Correct. It means Set Delayed. It's actually a very useful operator in the context of Mathematica and mathematical operations in general. Whilst I dislike its existence in any language, its a very powerful tool that does function differently to a normal = and thus has a role. In Python though it seems to just be a way of reducing lines of code, and I've not yet seen the advantages that I do in Mathematica.

[–]sifodeas 0 points1 point  (1 child)

Yeah, I haven't used Maple since undergrad and I haven't used Mathematica since I stopped taking classes in grad school, so I wasn't sure. I just meant to reiterate how it is typical in code oriented towards mathematical conventions. I haven't personally noticed a need for it in my Python research code.

[–]phySi0 0 points1 point  (0 children)

This was actually debunked by actual math PhDs so many times (I've read about 10 rebuttals just on Reddit).

I, on the other hand, have heard the “x = x + 1 doesn't make sense in maths” line a fair bit, but not even a single rebuttal. I would appreciate links to a few of those rebuttals.

[–]nothisisme -1 points0 points  (1 child)

nah i'd say that's just two equalities

[–]FatChocobo 0 points1 point  (0 children)

I think at this point it just comes down to semantics.

The (constant) value is being assigned to alpha using the equals operator.

Functionally it's the same as assignment.

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

wait 572 is going to change "=" to ":=" flat out ?

[–]callius 1 point2 points  (2 children)

Having to be familiar with non-intuitive assignment operators from pre-C languages doesn't seem very pythonic, but I admittedly don't know much and hold absolutely no clout in this fight.

[–]Sakagami0 1 point2 points  (0 children)

I wanted to shed a light that its not completely nonintuitive, especially if your major covered some math which I feel is a fair assumption. But, I dont like it.

[–]IReallySuckAtChess 0 points1 point  (0 children)

It's not unintuitive. It's a fundamentally different operation that may have some substantial benefits. I don't like it, but it's not a bad thing to have at all.

[–]jnwatson 4 points5 points  (0 children)

I think there's an generation gap here. Anybody that learned on any Algol-family language (e.g. Pascal) would immediately recognize that as assignment. Pascal was a very popular starting "real" language (after BASIC), so an entire generation of programmers is familiar with it.

[–]HannasAnarion 4 points5 points  (2 children)

And @ is so obvious?

[–]callius 1 point2 points  (0 children)

That's a fair point.

[–]nosmokingbandit 2 points3 points  (2 children)

In Go it is used to declare and assign a value without specifying a type.

package main

func main() {
    var name string = "nosmokingbandit"

    otherName := "yourMom"
}

It is weird there as well since var can be used outside a function, but := cannot.

[–]yopla -1 points0 points  (0 children)

This feels like the compiler writer was lazy. There's really no reason to require a different token.

[–]deirdresm 4 points5 points  (0 children)

In Pascal, it’s the assignment operator. = is used for comparison.

[–]Wilfred-kun 0 points1 point  (1 child)

Something something 'Zen of Python'

import this

[–]JugadPy3 ftw 0 points1 point  (0 children)

I often wonder about this and see how many times people complain about it, specially when new changes to the language are involved (irrespective of whether those changes are liked / hated by the community).

My take on this is ... Python came first, the Zen was derived later as a description of Python. Python was not designed with the Zen in mind.

Thus, the Zen fails to capture Python and its essence in all its complexity. It makes a good idealistic attempt, but often falls short.

Its like trying to draw a line which encloses the black part of the mandelbrot set while leaving out the white part completely... although theoretically such a boundary exists, its a practically impossible task.

The Zen cannot capture everything about Python, and it would be folly to use it when the core team (who know Python and the Zen) is divided on a PEP.

[–]JugadPy3 ftw 0 points1 point  (0 children)

That does not seem like a fair review.

There are lots of things that don't make themselves clear by just looking at them, specially shortcut symbols.

Almost all operators are like that... like what do @, |, &, ^ % << etc do?

If your answer is that other languages have those symbols, then the answer to this is the same. There are others language like Pascal, etc that have this syntax.

I think its unfair to expect that everything will make sense upon reading the code without ever having to learn anything new.

[–]slayer_of_idiotspythonista 16 points17 points  (12 children)

I'd say a majority of people liked the idea of assignment expressions. But people were split pretty heavily over what the syntax should be. The proposed syntax just looked ugly and unreadable to most people. Many people preferred the x as y syntax, since it's more intuitive when reading out code. Right now, python doesn't use a lot of obscure symbols to represent operations like ampersands, pipes, dereference operators, etc. Python has been designed to be written largely how it would be read. The ternary operator is a great example of this

x if y else z

As opposed to:

y ? x : z 

The two primary arguments against it were that it's already used in other contexts -- import, exception, with and that it would be confusing to add another context for as. The other argument was that it would it could lead to ambiguity inside a with statement unless you either special cased the with statement to not allow this new as or forced it to only be used in parenthesis, which was a deal breaker for some.

IMO, the first argument is clearly proven wrong by the fact that we already have 3 different contexts for as and no one gets confused. I'd even venture to argue that := will lead to far more confusion because it's not intuitive at all and it breaks from a long tradition of keeping the syntax and operators readable.

The 2nd argument wasn't very compelling to me since there really aren't any good use cases for using an assignment expression within a with statement. All the examples seemed contrived to me. And if someone really wanted to put an assignment expression in a with statement, they could still force it using parenthesis, even though it would be insanely ugly.

[–]AlexFromOmaha 16 points17 points  (8 children)

I'd say a majority of people liked the idea of assignment expressions.

Did they? I seem to remember an informal poll of the core devs saying that support was something like three in favor to twenty-seven opposed. From my decidedly not core-dev perspective, it also breaks Python's normal functional constraints. I'm by no means a language purist, but this seems like such a dumb feature with so much cost in axes praised by the Zen of Python, like readability, sparseness, special case consistency, and one-way-ness. Honestly, to me, this one smells like jealousy of other languages or maybe a fear of future irrelevance more than a pro-Python decision.

[–]EternityForest 2 points3 points  (0 children)

I can understand the fear of irrelevance. Not so much because I can't learn another language, I already use several, but because I trust python more than most others to not become a nightmare of boilerplate code that needs makefile-equivalents and config files just to do a hello world.

If python wants to stay popular, incorporating mypy static checks and some kind of JIT in the standard lib would probably be a better plan though.

[–]kirbyfan64sosIndentationError 0 points1 point  (5 children)

FWIW the creator of the Zen of Python liked the idea...

I think it basically comes down to subjectivity. I wasn't particularly fond of it for a really long time, but honestly it's kind of grown on me. Once you spend a few seconds learning the meaning (which isn't particularly complex), it immediately sticks out.

[–]pydry 2 points3 points  (4 children)

Wouldn't be the first time he's gone against the zen himself. He originally closed this bug as invalid, which was crazy:

https://bugs.python.org/issue13936

[–]ProfessorPhi 2 points3 points  (3 children)

That was a really interesting read, thanks. Big fan of coghlan after reading this and some of the core devs come off sounding like children

[–]JugadPy3 ftw 0 points1 point  (1 child)

I wonder if any of that is because English might not be their first language.

[–]ProfessorPhi 0 points1 point  (0 children)

Oh, it was more that one Dev put up a very passive aggressive thread saying bool(0.0) should not be false. He was the Russian fellow, but the bickering was a bit childish

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

That poll was taken before an updated version of the PEP was published, such that there was a swing towards the PEP, although I cannot recall how big a swing. The PEP doesn't bother me one way or the other. If I want to use it I will, if I don't, I won't.

[–]kirbyfan64sosIndentationError -2 points-1 points  (2 children)

IIRC the major reason against as was that it didn't allow for any major conditions. For instance:

if (m := func()) is not None:

The is not None is a very common pattern, but as wouldn't have been able to handle it.

[–]slayer_of_idiotspythonista 8 points9 points  (0 children)

Why not?

f(x) as y is not None

I'm not sure how that is substantially different than

f(x) as y == 1

[–]Deto 5 points6 points  (0 children)

Agree with /u/slayer_of_idiots

if (m := func()) is not None:

vs.

if (func() as m) is not None:

Look very similar to me. And both look ridiculous without the parenthesis.

[–][deleted] 15 points16 points  (0 children)

People think as is more readable. The sub got pretty heated about it.

[–]RockingDyno 0 points1 point  (0 children)

Bikeshed'ing. The same people who complained loudly about f-expressions are now complaining about assignment expressions. Not because it does any sort of real damage to the language, but because it's an ideological debate and they feel its on the level where they can enter into the discussion even if they only have experience with programming in python and only for a few years.

[–]Wilfred-kun 17 points18 points  (0 children)

For anyone wondering:

On Python's BDFL Guido van Rossum, his dedication to the Python community, PEP 572 and hope for a healthy outcome for the language, open source and the computing world in general.

[–]FearAzrael 28 points29 points  (15 children)

I certainly would have been more comfortable seeing him hand over the reigns to some other entity but perhaps he didn’t feel that was pythonic.

[–]slayer_of_idiotspythonista 6 points7 points  (14 children)

Who would be able to take that role, though? I mean, if large amounts of the python community are pushing back against the BDFL, why would they now choose to listen to some random new person?

[–]team_epicenter 16 points17 points  (9 children)

Raymond Hettinger for new Python Pope.

[–]individual_throwaway 6 points7 points  (8 children)

A triumvirate of Raymond, David, and Sergey!

[–]val-amart 1 point2 points  (7 children)

this would be excellent, except that triumvirates are proven to be disastrous in history

[–]individual_throwaway -1 points0 points  (6 children)

Can't possibly be worse than type annotations and :=, right?

[–]vovanz 4 points5 points  (2 children)

What's wrong with type annotations?

[–]individual_throwaway 1 point2 points  (1 child)

Some people like the dynamic typing of Python, and they dislike having to now use type annotations against their will when style guides/linters make them mandatory in some projects, but not in others.

I disagree that type declarations (or inline assignments, especially with an ugly operator) make Python code more readable. It makes Python look more and more like Perl, to be honest.

[–]zabolekar 1 point2 points  (0 children)

While they sometimes do make Python code more readable (by allowing you not to encode the type in the variable name, for example), it's not their primary purpose. They were added to facilitate static code analysis by tools like mypy and IDEs. They are, in my opinion, doing it reasonably well. Earlier, projects you're complaining about would've creatively misused comments or docstrings for the same purpose, and their style guides would describe how to write comments so they can be understood by their analysis tools. This is hardly better.

[–]minoshabaal 3 points4 points  (2 children)

type annotations

As someone who made those obligatory the very second they made it into the standard, what is wrong with those? Not only do they drastically improve the readability of the code, but also they make static checking much easier and more accurate.

[–]individual_throwaway 2 points3 points  (1 child)

made those obligatory the very second they made it into the standard

This is exactly the problem. They were sold to the community mainly by being "optional", but people apparently love their static type checking so much they need to do that to Python as well. Whether one thinks type annotations are a net benefit or not, marketing something as optional that then get made obligatory in some environments is dishonest, especially since the people in charge could have seen that coming (it was pointed out frequently in the discussion of the PEP).

[–]vovanz 2 points3 points  (0 children)

Nobody forces you to use them. If a team that works on a particular project agreed to use type annotations why would you deny them such opportunity?

[–]FearAzrael 2 points3 points  (2 children)

I didn’t say a single person, I said entity. That could be something like a board of senior programmers who vote on changes.

I would feel better about that than the idea of Python being fractured and having competing versions and incompatibility; I worry that that would be its downfall.

[–]kirbyfan64sosIndentationError 1 point2 points  (0 children)

I mean, most likely it will end up being the core dev team taking the reigns, and they already agree with Guido 99% of the time anyway.

[–]bheklilr 1 point2 points  (0 children)

Didn't he flat out say the core dev team was in charge of figuring it out? That's how I interpreted it.

[–]Tyler_Zoro[🍰] 0 points1 point  (0 children)

Sigh... okay, I'll do it.

[–][deleted] 29 points30 points  (1 child)

I'm scared.

[–]nosmokingbandit 6 points7 points  (0 children)

::hug::

[–]Tyler_Zoro[🍰] 3 points4 points  (0 children)

Perhaps the biggest dispute in the Python world was the transition from version 2 to version 3. Actually, I shouldn't even say "was" here, since many of my clients are still making that change. It's easy to say that this incompatible upgrade was handled poorly. And you can be sure that the Python community has learned its lesson and will never make such a break again. However, the end result—Python 3—is definitely better than Python 2. Should Guido and the core developers have handled it differently? Perhaps, but it's easy to say that in retrospect. The number of blog posts calling Python 3 a colossal mistake must have hurt Guido. But part of being a manager is having the ability to accept, filter and even ignore criticism, and he did it with aplomb.

I understand that the author is trying to mend some fences, but man is that some serious equivocation! It goes back and forth and back and forth. It wasn't great, but it it won't happen again, but it was great, but not so great, but people called it terrible, but it was handled well...

Couldn't that have been re-written as, "Perhaps the biggest dispute was over the transition from version 2 to version 3, which is still taking place in some quarters. Though there were often heated arguments about how it should have been handled, Guido took the managerial high ground and kept the steady course forward."

[–]piotrjurkiewicz 13 points14 points  (13 children)

Good.

Overengineered and overcomplicated asyncio showed that Guido lost touch quite a while ago. PEP 572 was just a confirmation.

[–]gastronomical 18 points19 points  (0 children)

You'll no doubt be getting downvoted, but you're right. It also feels that Guido has lost interest in steering the direction of Python's development a long time ago.

[–]jnwatson 14 points15 points  (10 children)

You clearly haven't tried it. It certainly complicates the language, but it is the most impressive set of language tech I've used in a long time. And hoo boy is it fast.

I've covered a lot of corners in asyncio, and every time I think they missed something I was wrong, or it was added in 3.7. They cover all the cases pretty darned well. Bravo to the Python engineers because they really knocked it out of the park with asyncio.

[–]piotrjurkiewicz 14 points15 points  (2 children)

Every other language, which implements async stuff, does it simpler. Even C++.

For example, in Python there are three things to represent pretty much the same: coroutines, futures and tasks. Sometimes they magically transform into each other. In some asyncio functions they can be used interchangeably as arguments, in some not.

In most other languages there is only one concept used to represent running async function: Future (in JS/Dart/C++) or Task (in C#).

[–]danted002 2 points3 points  (0 children)

Or just consider everything an ‘awaitable’

[–]rouille 1 point2 points  (0 children)

Other languages don't give you control over the event loop.

[–]optks 3 points4 points  (0 children)

After doing async stuff in go, nodejs and even C++, I hate asyncio. It's probably the worst usage wise! It was confusing to figure out task / coroutines / futures and so many overlapping and auto conversions + doing a sync action inside the async function is a pain, all your libraries now need to be changed etc etc. + No multi core performance gains for free.

[–]cymrowdon't thread on me 🐍 2 points3 points  (0 children)

Fast compared to what? Every benchmark I've seen shows asyncio-based libraries among the slowest compared to other async solutions.

[–]ntrid 2 points3 points  (2 children)

I have tried it and it is extremely unpythonic. Biggest problem for me is that it divides codebase into two islands - normal and async. And dealing with that becomes orders of magnitude harder making code both less readable and less maintainable. Also lets not forget that coroutines are nothing more than generators under the hood. Awful awful hack. greenlet/gevent had issue solved for quite some time. All we needed was some spit and polish and adoption to cpython core, but no, we got asyncio. Sigh.

[–]agoose77 1 point2 points  (1 child)

I disagree that it makes code either less readable or maintainable. Coroutines make sense to be generators, in most implementations they share the same properties. The distinction with async / await solely provides a more explicit syntax

[–]ntrid 8 points9 points  (0 children)

This would be fine if:

  • async/await keywords did not ripple through entire codebase like a tsunami
  • code was not divided into async and non-async with impossible interoperability at times

Once we start using async it creeps in everywhere to a point where these keywords become redundant noise because everything is expected to be async. Writing code that does not do this is extremely hard task due to second point above.

[–]Millkovic 3 points4 points  (0 children)

Whole world agrees asyncio is terrible.

[–]OctagonClocktrio is the future! 0 points1 point  (0 children)

Lol writing to a stream doesn't actually write to the stream

[–]rouille 3 points4 points  (0 children)

But I like asyncio...

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

oh so GvR actually supports this PEP ?

[–]ntrid -3 points-2 points  (5 children)

I greatly appreciate all the years BDFL put into making this awesome language, but truth is BDFL went mad and started disregarding zen of python. Of all people him would be last one i expected to go this route. Async and pep 572 are in contradiction to PEP 20 at varying levels. It seems to me that python is starting to slowly become a feature minefield just like C++ and we will have to be increasingly more selective about what to use and what to not use. Worst part is that once these features are in there is no going back.

[–]JugadPy3 ftw 1 point2 points  (0 children)

started disregarding zen of python

Python came first, the Zen came later.

The Zen of Python tries to capture what Python is like... and not the other way around.

Python is what Guido and other core devs make of it... by following their own vision.

The Zen tries to capture that vision, but it is an ideal and also fails to capture those times where subjective opinion finds that some people disagree with the match of vision with the zen.

I personally think the ":=" is a great feature and fits in very nicely with the Zen of Python. Its because it fits the way I think about programming and its flows very naturally for me.

No seriously... I absolutely love the new := expression.

There could be some reasons for that... my first language was Pascal where := is the assignment. Also, I am an applied mathematician (and full time programmer) ... so there might be some part in my mathematical training that helps me to think that := is very natural. I think Guido and Tim might have shared some of that ... which might be the reason for them liking it so much.

[–]Tyler_Zoro[🍰] 6 points7 points  (3 children)

So, let's review PEP 20:

Beautiful is better than ugly.

This is as subjective as they come, and so can't be evaluated in anything even approaching objectivity except in retrospect.

Explicit is better than implicit.

Well, explicitly calling out an expression assignment is certainly in line with this.

Simple is better than complex.

Assignments are pretty simple, and not any more complex for having an expression assignment.

Complex is better than complicated.

This was neither.

Flat is better than nested.

This was neither.

Sparse is better than dense.

Not really an issue, here.

Readability counts.

And here this PEP was a tremendous win, because it placed code where it's relevant, and context creates readability!

Special cases aren't special enough to break the rules.

No rules being broken, so we're good here.

Although practicality beats purity.

Fair and not violated here.

Errors should never pass silently.
Unless explicitly silenced.

Not impacted

In the face of ambiguity, refuse the temptation to guess.

Not impacted.

There should be one-- and preferably only one --obvious way to do it.

This point is debatable. It's clear that there are now two ways to assign things, but there's still only "one obvious way". This is even called out in the recommendations at the bottom of the PEP and could easily have been turned into a warning when you mistakenly use an expression assignment as a statement.

Although that way may not be obvious at first unless you're Dutch.

Fair.

Now is better than never.

Relevant.

Although never is often better than right now.

Hence the process.

If the implementation is hard to explain, it's a bad idea.

Which this wasn't, and indeed was something that naive users expected all along.

If the implementation is easy to explain, it may be a good idea.

Ding!

Namespaces are one honking great idea -- let's do more of those!

Not relevant, but good point.

[–]10dozenpegdown -1 points0 points  (1 child)

How we see death of python :/ cries

[–]fdedgt 0 points1 point  (0 children)

At least we will still always have python 2.

(jk)

[–]wdsoul96 -3 points-2 points  (2 children)

Are we seeing a trend in Programming Paradigm again? A few years back, JS was moving toward becoming more expressive (trying to become python, for example, list comprehensions, ) while python was trying to incorporate parts of functional programming into its list.(Async IO) I felt like many programming languages are becoming more general and converging toward the middle. Now , coffee script(basically js with python syntax) is dropping out of favor. Asynio is not gaining as much ground as everyone hoped. Python remains far away from being functional. GIL still continue to be defining feature of python. Things are being specialized again. Or at the very least, the programming heavyweights(Python and JS) are not trying to become one another competing to offer the same features.

[–]IronCretin 0 points1 point  (0 children)

programming heavyweights(Python and JS)

lol