kbd 5 years ago

Despite controversy, walrus operator is going to be like f-strings. Before: "Why do we need another way to..." After: "Hey this is great".

People are wtf-ing a bit about the positional-only parameters, but I view that as just a consistency change. It's a way to write in pure Python something that was previously only possible to say using the C api.

  • stefco_ 5 years ago

    f-strings are the first truly-pretty way to do string formatting in python, and the best thing is that they avoid all of the shortcomings of other interpolation syntaxes I've worked with. It's one of those magical features that just lets you do exactly what you want without putting any thought at all into it.

    Digression on the old way's shortcomings: Probably the most annoying thing about the old "format" syntax was for writing error messages with parameters dynamically formatted in. I've written ugly string literals for verbose, helpful error messages with the old syntax, and it was truly awful. The long length of calls to "format" is what screws up your indentation, which then screws up the literals (or forces you to spread them over 3x as many lines as you would otherwise). It was so bad that the format operator was more readable. If `str.dedent` was a thing it would be less annoying thanks to multi-line strings, but even that is just a kludge. A big part of the issue is whitespace/string concatenation, which, I know, can be fixed with an autoformatter [0]. Autoformatters are great for munging literals (and diff reduction/style enforcement), sure, but if you have to mung literals tens of times in a reasonably-written module, there's something very wrong with the feature that's forcing that behavior. So, again: f-strings have saved me a ton of tedium.

    [0] https://github.com/python/black

    • lewiscollard 5 years ago

      For me, the hugs thing about f-strings was that invalid string format characters become a compile time error (SyntaxError).

        print('I do not get executed :)')
        f'{!}'
      
      
        File "stefco.py", line 2
          f'{!}'
          ^
        SyntaxError: f-string: empty expression not allowed
      
      This has the pleasing characteristic of eliminating an entire class of bug. :)
    • bulatb 5 years ago

      > If `str.dedent` was a thing

      Have you looked at textwrap.dedent?

      • stefco_ 5 years ago

        Yes! `textwrap.dedent` is great. On further reflection `wrap` is actually more useful for this kludge (see below). But my point is that that's a whole import for a kludge. Compare the f-string ideal (by my standards):

          raise ValueError("File exists, not uploading: "
                           f"{filename} -> {bucket}, {key}")
        
        ...which is short enough that it's readable, and it's clear where exactly each variable is going. It's the single obvious solution, so much so that I don't spend a second thinking about it (very Pythonic!). Compare it to using `str.format` with the same continued indentation:

          raise ValueError(("File exists, not uploading: {filename} -> "
                            "{bucket}, {key}").format(filename=filename,
                                                      bucket=bucket,
                                                      key=key))
        
        Even this minimal example looks terrible! Remember that a lot of exceptions are raised within multiply-nested blocks, and then format pushes things farther to the right (while also ruining your automated string-literal concatenation, hence the extra parentheses), leaving very little room for the format arguments. You can use a more self-consistent and readable indentation strategy:

          raise ValueError(
              (
                  "File exists, not uploading: {filename} -> "
                  "{bucket}, {key}"
              ).format(filename, bucket, key)
          )
        
        This is unquestionably more pleasant to read than the former, but it's 3 times longer than the simple f-string solution, and I would argue it is not any more readable than the f-string for this simple example. My point with having a `str.wrap` builtin is that at least you could use the docstring convention of terminating multi-line strings on a newline, which would get rid of the string concatenation issues while leaving you a consistent (albeit diminished by the "wrap" call) amount of rightward room for the `format` args:

          raise ValueError("""File exists, not uploading: {filename} ->
                           {bucket}, {key}
                           """.dedent().format(filename=filename,
                                               bucket=bucket, key=key))
        
        Maybe a little bit better than the first one, especially if you're writing a longer docstring and don't want to think about string concatenation. But still a kludge. You can use positional formatting to shorten things up, but the fundamental weakness of `str.format` remains.
        • bpchaps 5 years ago

          Here's a clean way to do that:

            str_fmt = "File exists, not uploading: {filename} -> {bucket}, {key}"
            fmt_vals = dict(filename=filename, bucket=bucket, key=key)
            raise ValueError(str_fmt.dedent().format(**fmt_vals))
          • stefco_ 5 years ago

            This is somewhat cleaner, and I also use this idiom when things get ugly with the inline formatting shown above. But my point is that none of these are very elegant for an extremely common use case. Throw this block in the middle of some complex code with a few try/except and raise statements and it still looks confusing. Having two extra temp variables and statements per error in a function that's just doing control flow and wrapping unsafe code can double your local variable count and number of statements across the whole function. AFAIK, there has been no elegant solution to this common problem until f-strings came around; the only decently clean one is using printf-style format strings with the old-style operator, but outside of terseness I find it less readable.

          • JoBrad 5 years ago

            Alternate “clean” way, but sort of hacky.

              raise ValueError(“File exists, not uploading: {filename} -> {bucket}, {key}”.format(**locals()))
        • Dylan16807 5 years ago

          f-strings are nice, but when the problem is indenting too far, what if you just... didn't do that?

            raise ValueError(("File exists, not uploading: {filename} -> "
                "{bucket}, {key}").format(filename=filename, bucket=bucket, key=key))
  • choppaface 5 years ago

    Was the walrus operator really worth "The PEP 572 mess"? https://lwn.net/Articles/757713/

    That post makes a few things very clear:

    * The argument over the feature did not establish an explicit measure of efficacy for the feature. The discussion struggled to even find relevant non-Toy code examples.

    * The communication over the feature was almost entirely over email, even when it got extremely contentious. There was later some face-to-face talk at the summit.

    * Guido stepped down.

    • contravariant 5 years ago

      It may not have been a fair trade, but then it wasn't a trade in the first place. Those all seem to be problems with the process itself, meaning that it could have happened any time a contentious feature came up, this just happened to be the one to trigger the problem.

      • choppaface 5 years ago

        I agree that a mess looked (sadly) inevitable based upon that post and some of the other surrounding context. E.g. Guido citing Yoda conditions, how dumb that game can be, and getting ignored.

        But just because the feature shipped and design-by-committee is upon us doesn't mean we need to accept the outcome. Why couldn't there have been a more evolutionary path for this feature? For example, there is surely a way to write a prototype library to accomplish the same effect with slightly different syntax. (How about a single function `walrus(a, b)` that does what `:=` does?). Then let real user adoption drive the change. Maybe somebody will discover case statements from scala and want that instead.

        I hope the committee models some amount of their work after WG21. C++ hasn't evolved so effectively because some people were magic visionaries. For the past decade, C++ has mostly ridden on the proven success of boost. And skipped a lot of the parts of boost that suck.

  • heydenberk 5 years ago

    I'd used f-string-like syntaxes in other languages before they came to Python. It was immediately obvious to me what the benefit would be.

    I've used assignment expressions in other languages too! Python's version doesn't suffer from the JavaScript problem whereby equality and assignment are just a typo apart in, eg., the condition of your while loop. Nonetheless, I find that it ranges from marginally beneficial to marginally confusing in practice.

    • fny 5 years ago

      I love string interpolation! But this seems to take it to a bizarre level place just to save a few keystrokes. Seriously, how is f"{now=!s}" substantially better than f"now={str(now)}"?

      Ergonomically, I see little benefit for the added complexity.

      • sammorrowdrums 5 years ago

        It really feels like it's very explicit at this point that you want to cast whatever value interpolated into your format string to a string...

        I don't want a type error for the most clear use case, in the same way I don't want one for print, because if I wanted a behaviour other than the basic string representation then I would still need to call something differently anyway.

        Given that explicit control of the __str__ method is also baked into the language it's also very clear what to expect.

        I like type errors when handling something like '1' + 1 because the JavaScript alternative is surprising and hides bugs. No surprises that a string formatter would coerce to string for me automatically (although I get that's maybe just personal feeling).

        I love the f strings, they have made my codebase cleaner and clearer. Definitely a pythonic win.

        • n3k5 5 years ago

          In GP's example, the call to str() isn't there to make sure you get a string instead of causing a type error; it's there to substitute str() for repr() (which also returns a string). Considering that this feature is mainly meant to make 'print debugging' more convenient, it makes sense that repr() is the default choice.

      • airstrike 5 years ago

        Readability counts, though I agree Explicit is better than implicit.

        Special cases aren't special enough to break the rules, Although practicality beats purity.

      • hermitdev 5 years ago

        I agree that the simple examples don't show much benefit, but imagine if you had a really complex expression. I can see the value there.

    • agumonkey 5 years ago

      I'm trying to write an elisp macro because yes.. f-strings are too convenient

  • Scarblac 5 years ago

    By itself I agree, every now and then you write a few lines that will be made a little shorter now that := exists.

    But there's a long standing trend of adding more and more of these small features to what was quite a clean and small language. It's becoming more complicated, backwards compatibility suffers, the likelyhood your coworker uses some construct that you never use increases, there is more to know about Python.

    Like f-strings, they are neat I guess. But we already had both % and .format(). Python is becoming messy.

    I doubt this is worth that.

    • vorticalbox 5 years ago

      they should pick f and put depreciation warnings on the other two, python is getting messy.

      • uranusjr 5 years ago

        They can’t just deprecate the other two; f-string’s nature precludes it from being used in situations where formatting needs to occur lazily, e.g. i18n. This is the same reason why other languages with string interpolation also keep a format method around, e.g. Swift’s String(format:). I guess you could argue that they should at least deprecate %-formatting, and this has indeed been raised multiple times, even prior to f-string’s introduction, but the power of Backwards Compatibility Gods are still strong there, for better or for worse.

        • heavenlyblue 5 years ago

          Nothing stops one from evaluating f-strings lazily. They could simply return a format string with parameters captured instead of interpolated string.

          • hjk05 5 years ago

            They could... but then they wouldn’t return the interpolated string, and they’d be just like using format, just saving the characters “.format” which ruins the exact thing people like about them.

            • wodenokoto 5 years ago

              Can you elaborate on the exact thing people like about f-strings, because I honestly thought it was saving having to write `format`

            • heavenlyblue 5 years ago

              Nah - you're clearly not using Python enough - the issue with current format is that of the identity of the arguments passed to it.

              I need to do 2 changes every time I change a format string - I need to remove the symbol representing it's placement and then I need to remove the argument passed to .format.

              Also old formatting does not easily support arbitrary expressions in the placements, thus in order to get those you need to change the arguments passed to the .format.

              f-strings get rid of those issues altogether. What you're showing is whatever you have in the brackets - 0 indirection and thus less margin for (unnecessary) errors.

              • uranusjr 5 years ago

                I struggle to understand how what you talked about is relevant here. The problem parent talked about is how this laziness could be implemented without losing what makes f-string awesome right now. It’s not viable, which backs my reasoning why at least one alternative format method is required.

                That said, I also struggle to understand how you’d claim parent clearly not using Python enough, when your description of str.format shows a lack of understanding to it yourself. One of the advantages of str.format over %-formatting is exactly that you do not need to modify the arguments passed to str.format when removing components from the source string:

                    >>> '{0} {1} {2}'.format('a', 'b', 'c')
                    'a b c'
                    >>> '{0} {2}'.format('a', 'b', 'c')
                    'a c'
                
                Or preferably (using keyword arguments instead of positional):

                    >>> '{x} {y} {z}'.format(x='a', y='b', z='c')
                    'a b c'
                    >>> '{x} {z}'.format(x='a', y='b', z='c')
                    'a c'
                
                But again, this doesn’t matter to parent’s argument. Nobody is arguing with you that f-string is better than alternatives for what it can do; we are trying to tell you that there are things it can’t do, and you did not get it.
                • heavenlyblue 5 years ago

                  >> One of the advantages of str.format over %-formatting is exactly that you do not need to modify the arguments passed to str.format when removing components from the source string:

                  It's not the string that most of the developers care about, it's the presence of the arguments to that string. The issue they are solving is "I would like to see A, B and C", rather than the issue of "I have provided A, B and C - would you please hide B from the view".

                  >> But again, this doesn’t matter to parent’s argument. Nobody is arguing with you that f-string is better than alternatives for what it can do; we are trying to tell you that there are things it can’t do, and you did not get it.

                  Please elaborate on what the f-string can't do? You have not provided the answer in your post. In my opinion, the only issue f-strings haven't solved is capturing the arguments in lambdas (before interplation) instead of their direct values. You, on the other hand - do not provide a clear explanation.

  • ehsankia 5 years ago

    Was the controversy really about the need for the feature? I thought most people agreed it was a great feature to have, and most of the arguments were about `:=` vs re-using `as` for the operator.

    • pmart123 5 years ago

      I like "as" instead. I didn't realize that was on the table. To me, it seems more Pythonic given the typical English-like Python syntax of "with open(path) as file", "for element in items if element not in things", etc.

      • mixmastamyk 5 years ago

        It had some drawbacks, which a great majority of the time won't apply. I too would have preferred an "as" clause that limited to if-statements, maybe while, and comprehensions.

      • Noumenon72 5 years ago

        "if m as re.match(p1, line)" is not very English-like.

        • clinta 5 years ago

          Because the variable goes after the as. if re.match(p1, line) as m:

        • carver 5 years ago

          `if re.match(p1, line) as m`, maybe?

          • collinmanderson 5 years ago

            Yes, this is what I would expect. Much like a with statement.

    • linsomniac 5 years ago

      I don't know in this case, but I do know that the Python community tends to have strong opinions about things. The := resulted in Guido stepping down, which I think is a good indicator that there wasn't agreement that it was "a great feature to have" and just down to syntax... :-(

      • dual_basis 5 years ago

        To be fair, Guido stepped down because of the way the community reacted.

        "The straw that broke the camel’s back was a very contentious Python enhancement proposal, where after I had accepted it, people went to social media like Twitter and said things that really hurt me personally. And some of the people who said hurtful things were actually core Python developers, so I felt that I didn’t quite have the trust of the Python core developer team anymore."

        Source: https://www.infoworld.com/article/3292936/guido-van-rossum-r...

        Note that Guido also was in support of the walrus operator, it's not like he stepped down because he disagreed with it.

        • darkpuma 5 years ago

          It's really disappointing that people could get so worked up, over what is essentially deciding which color to paint the shed, that they chase off the project founder. I wonder if there is any way for open source communities to effectively promote the "take a step back and remember what really matters in life" approach to conflict resolution.

          • toyg 5 years ago

            Guido wasn't chased off, he is still in the core group. He just isn't BDFL anymore -- which, from a certain point of view, might be the best of both worlds. As a long-time python user and small-time advocate, I felt the walrus was a really bad decision.

          • Aozi 5 years ago

            >I wonder if there is any way for open source communities to effectively promote the "take a step back and remember what really matters in life" approach to conflict resolution.

            We've spent decades debating on the merits of spaces vs tabs, and Vim vs Emacs, and a ton of other completely pointless stuff.

            What you're hoping is just a pipe dream, people will get invested in the most petty and asinine stuff out there, and take it as a personal insult if you disagree.

    • kbd 5 years ago

      All discussion I've ever seen was about the need for the feature, not its spelling. I didn't even know "as" was proposed, but in fact it is an "alternate spelling" they considered[1] in the PEP.

      [1] https://www.python.org/dev/peps/pep-0572/#alternative-spelli...

      • mixmastamyk 5 years ago

        The idea was accepted quickly, the rest of the debate was on its spelling and scope.

  • linsomniac 5 years ago

    I've literally been wanting something like the walrus operator since I first started using Python in '97. Mostly for the "m = re.match(x, y); if m: do_something()" sort of syntax.

    • dual_basis 5 years ago

      I mean, that isolated example doesn't really demonstrate the benefit of a walrus operator does it? You could have just written "if re.match(x, y): do_something()". If you re-used the result of computation within the if statement, I feel that would be a better example, eg. "m = re.match(x, y); if m: do_something(m)".

      • linsomniac 5 years ago

        True enough, as you point out I would be expecting to do_something with m. :-)

  • brummm 5 years ago

    I think in certain situations the walrus operator will probably be useful. But it definitely makes code less legible, which makes me cautious. The only useful use case I have found so far is list comprehensions where some function evaluation could be reduced to only one execution with the walrus operator.

    • kbd 5 years ago

      > But it definitely makes code less legible, which makes me cautious.

      Disagree. In cases where it's useful it can make the code much clearer. Just yesterday I wrote code of the form:

          foos = []
          foo = func(a,b,c,d)
          while foo:
             foos.append(foo)
             foo = func(a,b,c,d)
      
      With the walrus operator, that would just be:

          foos = []
          while foo := func(a,b,c,d):
              foos.append(foo)
      
      Further, I had to pull out 'func' into a function in the first place so I wouldn't have something complicated repeated twice, so it would remove the need for that function as well.
  • craigds 5 years ago

    Yep, I can't wait to use the walrus operator. I just tried it out (`docker run -it python:3.8.0b2-slim`) and I'm hooked already.

    Also, it's times like these I'm really glad docker exists. Trying that out before docker would have been a way bigger drama

voldacar 5 years ago

Python looks more and more foreign with each release. I'm not sure what happened after 3.3 but it seems like the whole philosophy of "pythonic", emphasizing simplicity, readability and "only one straightforward way to do it" is rapidly disappearing.

  • teddyh 5 years ago

    “I've come up with a set of rules that describe our reactions to technologies:

    1. Anything that is in the world when you’re born is normal and ordinary and is just a natural part of the way the world works.

    2. Anything that's invented between when you’re fifteen and thirty-five is new and exciting and revolutionary and you can probably get a career in it.

    3. Anything invented after you're thirty-five is against the natural order of things.”

    ― Douglas Adams, The Salmon of Doubt

    • stakhanov 5 years ago

      It's wrong to frame this as resistance to change for no reason. See my other comment. I see some of this stuff as repeating mistakes that were made in the design of Perl. ...but there are quite few people around these days who know Perl well enough to recognize the way in which history is repeating itself, and that has at least something to do with age.

      • knome 5 years ago

        "resistance-to-change for-no-reason" vs "resistance-to change-for-no-reason" :)

        • DangitBobby 5 years ago

          This is possibly the best example of the ambiguity of language I've ever seen. Two contradictory meanings expressed in the exact same phrase, and both of them are valid in the broader context.

        • ByThyGrace 5 years ago

          Jeez. What number of people who read the same phrase with either of those two meanings then continue to form opinions and even make decisions based on the resulting meaning?

        • mr_crankypants 5 years ago

          Both of which, it's worth noting, are painfully obvious and uncharitable strawmen.

      • mr_crankypants 5 years ago

        Me, I am old enough to know Perl, and I've got plenty of one-line skeletons in my own closet. And it more-or-less entered the world already vastly more TMTOWTDI-y than Python is after 3 decades.

        FWIW, I tend to think of comparisons to Perl as being a lot like Nazi comparisons, only for programming languages. And I do think there's some wisdom to the Godwin's Law idea that the first person to make a Nazi comparison is understood to have automatically lost the argument.

        It's just that, at this point, Perl is both so near-universally reviled, and so well-understood to be way too optimized for code golf, that any comparison involving it is kind of a conversation-killer. As soon as it shows up, your best options are to either quietly ignore the statement in which the comparison was made, or join in escalating things into a flamewar.

        • tialaramex 5 years ago

          I wouldn't call it reviled. Perl makes for a poor general purpose programming language, it always did. You can write an HTTP server in Perl but you probably shouldn't. It's very good for what it was always intended for, those situations where you need to process some data, but like just once not every week for the rest of eternity.

          I've never regretted a Perl program that I wrote, used and discarded. And I've never been content with a Perl program I found I was still using a week after I wrote it.

    • bacon_waffle 5 years ago

      The point #1 is expanded on in Feral by George Monbiot. Basically, we have a tendency to see the outside world we grew up with as the way things naturally should be, ignoring that previous generations may have changed it to be that way. That sheep-grazed pastoral landscape is easy to view as a thing worth preserving, but to an ecologist it might be a barren waste where there used to be a beautiful forest.

    • tialaramex 5 years ago

      Forewarned is forearmed. I headed into adulthood watching out for such mirages. For example: Making sure to listen to pop music enough that it does exactly what pop music is supposed to do (worm its way into your subconscious) so I don't wake up one morning unaccountably believing that Kylie Minogue was good but Taylor Swift isn't.

      My understanding of Python will probably never be quite as good as my understanding of C, but I can live with that.

      • owl57 5 years ago

        How do you know to listen to Taylor Swift or whatever? In the last century it was easy to be in sync: you could just watch MTV. Is there something keeping the notion of pop coherent these days?

    • mehrdadn 5 years ago

      I don't think it's just >35-year-olds who find what's going on in Python against the natural order of things?

      • tachyonbeam 5 years ago

        I'm 34 and I don't like this, so it's definitely not only those above 35. Jokes aside, I would say I'm a minimalist and this is where my resistance comes from. One of the things that I dislike the most in programming is feature creep. I prefer smaller languages. I like the idea of having a more minimal feature set that doesn't change very much. In a language with less features, you might have to write slightly more code, but the code you write will be more readable to everyone else. Said language should also be easier to learn.

        IMO, the more complex a system is, the more fragile it tends to become. The same is true for programming languages. Features will clash with each other. You'll end up having 10 different ways to achieve the same thing, and it won't be obvious which direction to go.

        Furthermore, I did my grad studies in compilers. I've thought about writing an optimizing JIT for Python. I really feel like CPython is needlessly slow, and it's kind of embarassing, in an age where single-core performance is reaching a plateau, to waste so many CPU cycles interpreting a language. We have the technology to do much better. However, the fact that Python is a fast moving target makes it very difficult to catch up. If Python were a smaller, more stable language, this wouldn't be so difficult.

        • RhodesianHunter 5 years ago

          > In a language with less features, you might have to write slightly more code, but the code you write will be more readable to everyone else.

          I disagree with this, which is precisely why I prefer feature rich languages like Java or better yet Kotlin. It doesn't get much more readable than something like:

            users.asSequence()
              .filter { it.lastName.startsWith("S") }
              .sortedBy { it.lastName }
              .take(3)
          
          Now try writing that in Go or Python and compare the readability.
          • kragen 5 years ago

            Python is a little more readable, but both Python and Kotlin are perfectly clear in this case:

                sorted((u for u in users
                       if u.last_name.startswith("S")),
                       key=lambda u: u.last_name
                )[:3]
            
            If last_name is a function, which it often would be in Python, it gets better:

                sorted((u for u in users
                       if last_name(u).startswith("S")),
                       key=last_name
                )[:3]
            
            However, I think you probably got the sort key wrong if you're taking the first three items of the result. Maybe you meant key=abuse_score, reverse=True, or something.
            • elcritch 5 years ago

              I disagree this python version is as readable and here’s why. It’s about as many characters but more complex. The Kotlin version performs several distinct actions, each being clear to its purpose. These actions have the same syntax (eg requires less parsing effort). The Python version mixes at least 4 different language syntax/features, being list comprehension, if special form in the list comprehension, keywords, and lambda functions.

              On top of the lessened readability, the Kotlin version makes it very easy to add, subtract, or comment out lines/actions which really helps when debugging. The Kotlin version is almost identical in structure to how you’d do it in Rust, Elixir, etc.

              • brodsky 5 years ago

                I agree. I don't know Kotlin and am reasonably well versed in Python, yet I immediately grasp the Kotlin example as more readable, while having to squint at the Python one for a few seconds. (this is anecdotal of course, and does not account for the example possibly being contrived)

              • HelloNurse 5 years ago

                One thing that I like more in the Python version is that it contains less names: .asSequence and .take are replaced by operators of much greater generality, while the ugly implicitly declared identifier it is replaced by explicitly deciding that sequence elements are u.

                It should also be noted that Python would allow a more functional style, possibly leaving out the list comprehension.

              • kragen 5 years ago

                It's surprising to me that there are people who disagree with my opinion about this, but it suggests that my familiarity with Python has damaged my perspective. You're clearly much less familiar with Python (this code doesn't contain any list comprehensions, for example), so I think your opinion about readability is probably a lot more objective than mine.

                • DangitBobby 5 years ago

                  FWIW most of the programming I've ever done has been in Python, and while I have no trouble understanding either snippet, I think that the Kotlin snippet is much clearer in intent and structure.

                  • kragen 5 years ago

                    I certainly didn't mean to imply that only someone unfamiliar with Python could prefer the Kotlin version! Perhaps you thought I meant that, but I didn't.

                • Izkata 5 years ago

                  > this code doesn't contain any list comprehensions, for example

                  It does contain a generator expression though, which is the same as a list comprehension in general structure, but slightly more confusing because it doesn't have the relationship to lists that square brackets in a list comprehension would have given it.

                  • kragen 5 years ago

                    Yes, it shares the structure of a list comprehension, but has different semantics. In this case a listcomp would have worked just as well.

                    My point, though, was that not being able to tell the difference was a key "tell" that the comment author was not very familiar with Python — in some contexts, that would tend to undermine credibility in their comment (and then it would be rude to point it out), but in this context, it probably makes their opinion more objective.

                    • elcritch 5 years ago

                      Good point, though it's less my familiarity with Python and more that I tend to simplify and call generator expressions as list comprehensions unless the laziness is important to call out (meta laziness there? ;) ). Mainly since L.C.'s were first and describing the differences is tedious.

              • agumonkey 5 years ago

                I think you're all fighting for nothing here.

                The map filter chaining is obviously simpler, but python code is not that difficult and it's a no brainer task anyway.

                • elcritch 5 years ago

                  It's true the Python is still relatively easy. It may only take, say, 1.3 sec vs 1.1 to parse, but it adds up.

            • 59nadir 5 years ago

              This isn't very readable at all and certainly not any more readable than a chain of method calls, being that you've spread the operations out in different places. It's not even syntactically obvious what the `key` argument is passed to if one doesn't know that `sorted` takes it. None of those problems exist when piping through normal functions or chaining method calls.

              Python is for the most part overrated when it comes to these things, IMO. It's a nice enough language but it's aged badly and has an undeserved reputation for concision, readability and being "simple".

            • V-2 5 years ago

              C# supports both conventions (in LINQ) - I mean the Kotlin one from the grandparent comment, and the Python's from parent's.

              The method chaining syntax and the query syntax are alternatives. I think most devs lean towards the former, considered to be cleaner... whereas the latter is probably easier to learn in the beginning, to those unfamiliar with piping/functional style - owing to its SQL feel-alikeness.

              ReSharper would offer converting the latter to the former, and that's how I learned method-chaining LINQ back in the day.

          • mehrdadn 5 years ago

            A little off-topic but how does that work? Is 'it' a magic variable referring to the first argument? Never seen magic variables that blend into lambdas like that before... would've expected $1 or something like that.

            • sls 5 years ago

              The idea of anaphoric macros[1] is first found in Paul Graham's "On Lisp"[2] and is based on the linguistic concept of anaphora, an expression whose meaning depends on the meaning of another expression in its context. An anaphor (like "it") is such a referring term.

              I think if you like this idea, you will really like the book. Better still, you can download the pdf for free.

              [1] https://en.wikipedia.org/wiki/Anaphoric_macro [2] http://www.paulgraham.com/onlisp.html

            • RhodesianHunter 5 years ago

              Inside of any lambda that takes a single parameter you can refer to the parameter as 'it'. If you prefer to name your parameters you can do so as well, it's just slightly more verbose:

                users.asSequence()
                  .filter { user -> 
                    user.lastName.startsWith("S") 
                  }
                  .sortedBy { user -> 
                    user.lastName 
                  }
                  .take(3)
            • kragen 5 years ago

              Yeah, a bit of PG’s Arc influence in the wild.

              • riffraff 5 years ago

                I believe groovy made this popular rather than arc, and it's likely where kotlin's come from, due to being in the java ecosystem.

                • jnordwick 5 years ago

                  Most apl deviatives (j, k, q, a) all had implicit arguments for functions that didn't explicitly declare them (up to 3: x, y, and z).

                  Probably before then too.

                  • kragen 5 years ago

                    Dyalog APL too, but none of them call the implicit argument "it".

                • kragen 5 years ago

                  Groovy is from 2003. PG keynoted PyCon in 2003 talking about his progress on Arc: http://www.paulgraham.com/hundred.html. He had been talking about Arc online for a couple of years at that point, including in particular the convenience of "anaphoric macros" that defined the identifier "it" as an implicit argument.

                  (He'd also written about that more at length in the 1990s in On Lisp, but many more people became acquainted with his language-design ideas in the 2001–2003 period, thanks to Lightweight Languages and his increasingly popular series of essays.)

                  • earthboundkid 5 years ago

                    But surely Perl's $_ was way more influential than an obscure PG talk. I was reading PG way back in 2004, and I had never heard of anaphoric macros until now.

                    • kragen 5 years ago

                      Wait, you think that, in the context of programming language design, a PyCon keynote is an obscure talk? I don't know what to say about that. It might be possible for you to be more wrong, but it would be very challenging.

                      Anyway, I'm talking specifically about the use of the identifier "it" in Kotlin, not implicitly or contextually defined identifiers in general, which are indeed a much more widespread concept, embracing Perl's $_ and @_, awk's $0 (and for that matter $1 and $fieldnumber and so on), Dyalog APL's α and ω, Smalltalk's "self", C++'s "this", dynamically-scoped variables in general, and for that matter de Bruijn numbering.

                      • earthboundkid 5 years ago

                        > a PyCon keynote is an obscure talk

                        Compared to the existence of Perl, yes. Anyone who does any amount of Perl learns that $_ is the implicit argument ("like 'it'") to most functions. It's pretty much one of Perl's main deals. The talk has about 100K views on YouTube, which is pretty good, but Perl is in another league.

                • vorg 5 years ago

                  Too bad Apache Groovy itself didn't remain popular after popularizing the name "it" for the much older idea of contextually-defined pronouns in programming languages. Using the names of pronouns in English (like "this" and "it") is easier for an English-speaking programmer to understand than symbols like "$1" or "_". But because of Groovy's bad project management, another programming language (Kotlin) is becoming widely known for introducing the "it" name.

          • goatlover 5 years ago

            Pretty sure the Go community will be fine with not being feature rich, since simplicity, maintainability and getting new people up to speed matter more for them.

            • tonyedgecombe 5 years ago

              The go community have gone to far the other way for me, the endless repetition introduces its own complexity.

          • strokirk 5 years ago

            sorted(u for u in users if u.last_name.startswith("S"), key=lambda u: u.last_name)[:3]

            Though I will conceed that I also find the fluent interface variant nicer.

            • mehrdadn 5 years ago

              That doesn't parse :-)

          • andrewshadura 5 years ago

            You’re doing it wrong :)

              users.apply {
                  asSequence()
                  filter { it.lastName.startsWith("S")
                  sortedBy { it.lastName }
                  take(3)
              }
            
            (totally untested)
        • Scarbutt 5 years ago

          Furthermore, I did my grad studies in compilers. I've thought about writing an optimizing JIT for Python. I really feel like CPython is needlessly slow, and it's kind of embarassing,

          Many have tried and failed, Google and Dropbox to name a couple, and countless other attempts.

          • yjftsjthsd-h 5 years ago

            It lags a bit in releases, but I understood pypy to be essentially successful?

            • chc 5 years ago

              Yes, PyPy is fantastic for long-running processes that aren't primarily wrappers around C code. In my experience, the speedups you see in its benchmarks translate to the real world very well.

          • tachyonbeam 5 years ago

            Yes, and part of the reason they failed is the reason I pointed to: Python is a fast moving target, with an increasing number of features.

            • wvenable 5 years ago

              It's not the new features of Python that make it hard to optimize; it's the fundamental dynamic nature of the language that was there from day one. Syntactic sugar doesn't have an impact one way or the other on optimizing Python.

              • tachyonbeam 5 years ago

                The new features aren't just syntactic, they're also new libraries that come standard with CPython, etc. If you want to implement a Python JIT that people will use, you have to match everything CPython supports. Furthermore, since the people behind CPython don't care about JIT, you also can't count on them not adding language features that will break optimizations present in your JIT. You can't count on these being just "syntactic sugar". Even if you could though, in order to keep up it means you have to use CPython's front-end, or constantly implement every syntactic tweak CPython does.

                Lastly, AFAIK, CPython's FFI API is actually more of a problem than the dynamic semantics of the language. You can expose Python objects directly to C code. That makes it very hard for a JIT to represent said Python objects in an efficient way internally.

        • wvenable 5 years ago

          > In a language with less features, you might have to write slightly more code, but the code you write will be more readable to everyone else.

          That's not universally true. C# has more features than Java but is generally easier to read and the intent of the code is easier to follow. The lack of features, like properties or unsigned integers, leads to Java coders creating much more convoluted solutions.

          If languages with less features were universally better we would all be using C and BASIC for everything.

          • nitroll 5 years ago

            I think the importance is the orthogonality of the features. Eg. having so many ways to do string formatting or now multiple ways of doing assigments are not ortogonal and thus can be seen as cluttering.

      • hermitdev 5 years ago

        I'm 38, and I'm fine with these changes, and ive been using Python for +15 years.

        I can plainly see how these changes will actually make my code cleaner and more obvious while saving me keystrokes.

        I also don't think these changes are very drastic. They're opt-in, doesn't break anything and looks to lead to cleaner code. I love the walrus operator (not so sure about the name, but hey. C++ is getting the spaceship operator... As has been said, naming things is hard). To me, the change of print from a statement to a function has been the hardest Python chamge over the years. Just too much mental momentum. Even though ive been on Python 3 for years, I still make the mistake of trying to use it as a statement. That said, I think it was the right (if painful) move.

        I don't speak for everyone over 35, just myself.

      • serf 5 years ago

        theory : age itself with regards to computing has nothing to do with how old you act (with regards to computing), the time you spent doing a specific thing is what grows that 'characteristic'.

        Anecdote : i'm fairly young, but i've been involved with python long enough and traveled to enough pycons to be a bit jaded with regards to change within the language.

        I'm fairly certain it's only due to the additional cognitive load that's thrust upon me when I must learn a new nuance to a skill that I already considered myself proficient at.

        in other words : i'm resistant to change because i'm lazy, and because it (the language, and the way I did things previously) works for me. Both reasons are selfish and invalid, to a degree.

      • orangecat 5 years ago

        Conversely, some of us oldsters think the outrage is way overblown.

    • voldacar 5 years ago

      No, those aren't really the reasons for my reaction. And if I told you my age, you would probably switch your argument and say that I'm far too young to criticize ;)

    • dual_basis 5 years ago

      I am an example which supports this notion. I've done some Python programming about 10 years ago but then took a break from programming altogether for the last 9 years. Last year I got back into it and have been using Python 3.7, and I personally love all the most recent stuff. I hate having to go back to 3.5 or even 3.6, and I end up pulling in stuff from futures.

    • throw2016 5 years ago

      This 'resistance to change' catchall argument puts everything beyond criticism, and it can be used/abused in every case of criticism. It seeks to reframe 'change' from a neutral word - change can be good or bad - to a positive instead of focusing on the specifics.

      Anyone making this argument should be prepared to to accept every single criticism they make in their life moving forward can be framed as 'their resistance to change'.

      This kind of personalization of specific criticism is disingenuous and political and has usually been used as a PR strategy to push through unpopular decisions. Better to respond to specific criticisms than reach for a generic emotional argument that seeks to delegitimize scrutiny and criticism.

      • teddyh 5 years ago

        True, but this was not “specific criticism”. It was a general dismissing criticism without details, and so can be refuted with a similarly detail-less answer. A detailed criticism deserves a reasoned and detailed answer, but vague criticism gets a generic rebuttal.

    • whatshisface 5 years ago

      Does that mean someone born in 2008 will think C++ is simple and elegant?

      • mianos 5 years ago

        I am both a Python programmer and a C++ programmer. I have programmed professionally full time in one or the other for years at a time. I think C++ is now a much better language than when I learnt it first (cfront). In particular C++11 really fixed a lot of the memory issues with shared_ptr and std:: algorithms. It is a better language now if you are doing anything larger than then a program that takes more than a few weeks to write. On the other hand, I love python for everything else and some of the new stuff is great but making a new way to print strings over and over tells me some people have too much spare time or not enough real work to do. In my opinion formatting a string to print a debug statement should be as concise as possible whereas a lot of these fancier formatting systems are better suited to stuff that ends up staying for use by other people. Luckily there are ways to use ye olde printf style formatters in both for those times.

        • 59nadir 5 years ago

          C++ might be "better" now (I doubt it, to be honest, it just has more features that try to fix the issue at hand; that you're using C++), but it will never, ever get simpler or simple enough. They'd have to remove something like 75% of the language to end up with something that approaches simplicity and even then there are languages that would undoubtedly do those remaining 25% much better.

          I stopped writing C++ at some point in 2008/2009 but I still keep track of it to some extent and I'm continually surprised by the nonsense that is introduced into the language. The whole RAII movement, for example, is just one massive band-aid on top of the previous mistake of allowing exceptions, etc..

          It'd be mostly fine in the long run, but you have all these people using like 15% of C++ and complain about it all day long, making their libraries not usable from stuff that understands C (most of which have drastically improved on the whole paradigm). There's a solution here and it's not using whichever arbitrary percentage you've decided on of C++, it's realizing that there are way better languages with real interoperability in mind to talk about lower-level things.

      • philipov 5 years ago

        No, the claim is that it's ordinary and just part of the way the world works.

      • golergka 5 years ago

        Good point. I think it should be rephrased in basis of personal familiarity: people who learned C++ before they were 15 indeed think that it's simple and elegant.

    • cameronbrown 5 years ago

      Except that Python existed before I was born and I still appreciate the concept of 'Pythonic'. The language should stay true to its roots.

    • ineedasername 5 years ago

      * Anything that is in the world when you’re born is normal and ordinary and is just a natural part of the way the world works.*

      Yep, I entered the Python world with v2. I eventually reconciled myself to 2.7, and have only recently and begrudgingly embraced 3. Being over 35, I must be incredibly open minded on these things.

  • nerdponx 5 years ago

    Can you give an example of something like this happening to the language? IMO 3.6+ brought many positive additions to the language, which I also think are needed as its audience grows and its use cases expand accordingly.

    The walrus operator makes while loops easier to read, write and reason about.

    Type annotations were a necessary and IMO delightful addition to the language as people started writing bigger production code bases in Python.

    Data classes solve a lot of problems, although with the existence of the attrs library I'm not sure we needed them in the standard library as well.

    Async maybe was poorly designed, but I certainly wouldn't complain about its existence in the language.

    F strings are %-based interpolation done right, and the sooner the latter are relegated to "backward compatibility only" status the better. They are also more visually consistent with format strings.

    Positional-only arguments have always been in the language; now users can actually use this feature without writing C code.

    All of the stuff feels very Pythonic to me. Maybe I would have preferred "do/while" instead of the walrus but I'm not going to obsess over one operator.

    So what else is there to complain about? Dictionary comprehension? I don't see added complexity here, I see a few specific tools that make the language more expressive, and that you are free to ignore in your own projects if they aren't to your taste.

    • masklinn 5 years ago

      > F strings are %-based interpolation done right, and the sooner the latter are relegated to "backward compatibility only" status the better. They are also more visually consistent with format strings.

      No, f-strings handle a subset of %-based interpolation. They're nice and convenient but e.g. completely unusable for translatable resources (so is str.format incidentally).

      • joshuamorton 5 years ago

        What makes % better than .format for translations (and isn't something like Django's _(str) better anyway?

        F strings are obviously non-lazy, but _(tmpl).format(_(part)) seems fine?

        • masklinn 5 years ago

          `.format` lets you dereference arbitrary attributes and indices (I don't think it lets you call methods though), meaning you can run code and exfiltrate data through translated strings if they're not extremely carefully reviewed, which they often are not.

          % only lets you format the values you're given.

          > and isn't something like Django's _(str) better anyway

          They're orthogonal. You apply string formatting after you get the translated pattern string from gettext. In fact, Django's own documentation demonstrates this:

              def my_view(request, m, d):
                  output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
                  return HttpResponse(output)
    • ptx 5 years ago

      What would "do/while" look like in Python? Since blocks don't have end markers (e.g. "end", "}", etc.) there's nowhere to put the while expression if you want the syntax to be consistent with the rest of the language.

      • ben509 5 years ago

        One solution would be to borrow from Perl. You make a do block that executes once unless continued, and allow conditions on break and continue:

            do:
                thing()
                thing()
                continue if condition
        
        And you can now express "skip ahead" with a `break if X` as well.
        • adrianratnapala 5 years ago

          Yes, although you don't have to be so perlish as to do the if in that order

              do:
                  thing()
                  thing()
                  if condition:
                      continue
      • nerdponx 5 years ago

        I envisioned it like "if/else" or "for/else" or "while/else", where a "do" block must be followed by a "while" block.

            x = 0
            do:
                x += 1
            while:
                x < 10
        • toxik 5 years ago

          This completely contradicts the rest of Python grammar, and indeed many languages’ grammars. The consistent way would then be `while x < 10` but that too looks ridiculous. The issue is that you can’t have post-clause syntax in Python due to its infamous spacing-is-syntax idea.

          • ben509 5 years ago

            I'm not sure why the consistent way looks ridiculous.

                do:
                    body()
                    body()
                while x < 10
            
            It's just a compound statement consumes the trailing while clause.

            Decorators already precede a function (or class) definition[2], and one alternative for the ill-fated switch statement[1] was to have switch precede the case blocks to avoid excessive indentation.

            So there's plenty of precedent in the other direction.

            [1]: https://www.python.org/dev/peps/pep-3103/#alternative-3

            [2]: https://docs.python.org/3/reference/grammar.html

            • toxik 5 years ago

              I think you're really stretching it when you say "there's plenty of precedent," arguably there is none as the decorator syntax is pre-clause and thus poses no indentation reading issues. So too for the proposed switch statement syntax. Then there is the fact that the decorator syntax is perhaps the most alien of all Python syntax, sometimes criticized for being Perlesque, perish the thought (on account of it being introduced by creative interpretation of a single special character though, so perhaps unrelated.)

              My main gripe is the indentation. Your code reads as if the while condition is tested after the loop finishes. What if the while statement was part of the loop and could be placed arbitrarily?

                  do:
                      body1()
                      body2()
                      while x < 10
                      body3()
              
              IOW `do:` translates to `while True:` and `while x` to `if not x: break`.

              Addendum: I would also entertain forcing the `while` to be at the end of the loop -- as I'm not sure what this would do

                  do:
                      if foo():
                          while x < 10
              • ben509 5 years ago

                I think it's precedent because it's just a line after a block instead of before it. It certainly is a break from Python's "big outline" look.

                > What if the while statement was part of the loop and could be placed arbitrarily?

                If you're open to that, I had thought this was a bridge too far, but:

                    do:
                        body1()
                        break if some_condition
                        body2()
                        continue if some_other_condition
                
                Under that scheme, the semantics translate to:

                    while True:
                        do_body
                        break
                
                And, of course, the `break if` and `continue if` syntax would be general.
          • mkl 5 years ago

            Of course you can have post-clause syntax: if...else, try...except, for...else, etc.

            (Edit: Actually, I think I know what you were saying now, and those aren't quite the same thing as they need a line after them.)

            I do think the condition on the next line isn't the way to do solve this problem though (and I don't think it needs solving, while True: ... if ...: break does the job).

          • krferriter 5 years ago

            Why does `while x < 10` look ridiculous? It looks exactly like the syntax for regular while loops, just in this case it's after a `do:` block. And the example above yours looks like try/catch syntax, but tbh I like the one you suggested a bit more.

          • nerdponx 5 years ago

            You're right, it would be pretty weird to rely on implicitly "returning" a value from an expression like that.

            But I don't think having it all on one line would be that bad.

  • sametmax 5 years ago

    Most code still look like traditional Python. Just like meta programming or monkey patching, the new features are used sparingly by the community. Even the less controversial type hints are here on maybe 10 percent of the code out there.

    It's all about the culture. And Python culture has been protecting us from abuses for 20 years, while allowing to have cool toys.

    Besides, in that release (and even the previous one), appart from the walrus operator that I predict will be used with moderation, I don't see any alien looking stuff. This kind of evolution speed is quite conservative IMO.

    Whatever you do, there there always will be people complaining I guess. After all, I also hear all the time that Python doesn't change fast enough, or lack some black magic from functional languages.

    • wyldfire 5 years ago

      > Even the less controversial type hints are here on maybe 10 percent of the code out there.

      I think this metric is grossly overestimated. Or your scope for "out there" is considering some smaller subset of python code than what I'm imagining.

      I think the evolution of the language is a great thing and I like the idea of the type hints too. But I don't think most folks capitalize on this yet.

      • sametmax 5 years ago

        I mean 10% of new code for which type hints are a proper use case, so mostly libs, and targeting Python 3.5+.

        Of course, in a world of Python 2.7 still being a large code base and Python being used a lot for scripting, this will far from the truth for the entire ecosystem.

        • Quekid5 5 years ago

          The idea that types are hostile to scripting sounds really weird to me. Turtle[0] in Haskell is absolutely amazing for scripting -- especially if you pair it with Stack (with its shebang support) -- and it is as strongly typed as Haskell.

          There is a bit of learning curve (because, well, it's not shell which is what most people are used to), and you do have to please the compiler before being able to run your script, but OTOH, you'll basically never have that "oops, I just deleted my working directory because I used a bad $VARIABLE" experience.

          [0] http://hackage.haskell.org/package/turtle

    • dudul 5 years ago

      What's an example of black magic from functional languages?

  • llukas 5 years ago

    If you complained more specifically it would be possible to discuss. For what was described in article I don't see anything "foreign". Python was always about increasing code readability and those improvements are aligning well with this philosophy.

  • baq 5 years ago

    i've been hearing this since 1.5 => 2.0 (list comprehensions), then 2.2 (new object model), 2.4 (decorators)...

    happy python programmer since 1.5, currently maintaining a code base in 3.7, happy about 3.8.

    • spamizbad 5 years ago

      I cut my teeth on 2.2-2.4 and remember getting my hand slapped when 2.4 landed and I used a decorator for the first time.

      It was to allow only certain HTTP verbs on a controller function. A pattern adopted by most Python web frameworks today.

    • runxel 5 years ago

      That's especially funny given how everybody screams "that's not pythonic!!1!" nowadays when somebody does _not_ use a list comprehension...

  • Razengan 5 years ago

    The '*' and '/' in function parameter lists for positional/keyword arguments look particularly ugly and unintuitive to me. More magic symbols to memorize or look up.

    • riffraff 5 years ago

      I also cannot honestly think of a case where I want that behaviour.

      The "pow" example looks more like a case where the C side should be fixed.

      • masklinn 5 years ago

        > I also cannot honestly think of a case where I want that behaviour.

        There's plenty of situations where a named argument does not help, and encoding it can only hurt. It makes little to no sense to name the first argument to `dict.update` for instance. Or the argument to `ord`.

        That, incidentally, is why Swift added support for positional-only parameters (though it has no concept of keyword-or-positional).

        • Razengan 5 years ago

          > That, incidentally, is why Swift added support for positional-only parameters (though it has no concept of keyword-or-positional).

          Swift's syntax is a lot more intuitive and consistent:

              function(parameterWithImplicitlyRequiredLabel: Int,
                       differentArgumentLabel internalParameterName: Int,
                       _ parameterWithoutLabel: Int, 
                       variadicParameterWithLabel: Int...)
          
          which you would call as

              function(parameterWithImplicitlyRequiredLabel: 1, differentArgumentLabel: 2, 3, variadicParameterWithLabel: 4, 5, 6, 7)
          
          [0] https://docs.swift.org/swift-book/LanguageGuide/Functions.ht...
        • riffraff 5 years ago

          It does not help but doesn't hurt enough to grant a special syntax to avoid it.

          Yes, it limits your ability to rename a local variable, but that seems minor.

      • yxhuvud 5 years ago

        Or where the method should be exposed into several different methods.

  • jnwatson 5 years ago

    Beyond the older-than-35 reason, I think a lot of folks are used to the rate of new features because there was a 5 year period where everyone was on 2.7 while the new stuff landed in 3.x, and 3.x wasn't ready for deployment.

    In reality, the 2.x releases had a lot of significant changes. Of the top of my head, context managers, a new OOP/multiple inheritance model, and division operator changes, and lots of new modules.

    It sucks that one's language is on the upgrade treadmill like everything else, but language design is hard, and we keep coming up with new cool things to put in it.

    I don't know about Python 3.8, but Python 3.7 is absolutely amazing. It is the result of 2 decades of slogging along, improving bit by bit, and I hope that continues.

  • LaGrange 5 years ago

    In my experience, every technology focused on building a "simple" alternative to a long-established "complex" technology is doomed to discover exactly _why_ the other one became "complex." Also spawn at least five "simple" alternatives.

    Doesn't mean nothing good comes out of them, and if it's simplicity that motivates people then eh, I'll take it, but gosh darn the cycle is a bit grating by now.

    • orhmeh09 5 years ago

      Could you provide some examples? Without having had that experience, I’m having trouble picturing a concrete example that I would be sure is of the same kind.

      • LaGrange 5 years ago

        Nginx is probably my fav of the surviving-and-thriving ones. It still remains very distinct from Apache, but calling it simpler would be a large stretch.

        Projects like qmail discovered the reason in a somewhat _harder_ manner. And yes, I'd argue Python is yet another case, as it grew _at least_ as complex as Perl.

    • newen 5 years ago

      Haha, what was that quote? Something like, any language is going to iterate towards a crappy version of lisp.

      • tjalfi 5 years ago

        Greenspun's Tenth Rule[0]

        Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp. - Philip Greenspun

        [0] https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule

        • aitchnyu 5 years ago

          How would you subvert Greenspun in large codebases without Common Lisp? I once used Drools the rules engine which used a dynamic scripting language on Java objects. Python could have replaced that language, with much better tooling, errors etc.

  • amedvednikov 5 years ago

    I'm working on a language with a focus on simplicity and "only one way to do it": https://vlang.io

    The development has been going quite well:

    https://github.com/vlang/v/blob/master/CHANGELOG.md

    • jamesb93 5 years ago

      This is great! Thanks for your work. Can V be integrated into existing c++ projects? I work in audio and constantly working in c++ is tiring. I'd love to work in something like V and transpile down.

      • amedvednikov 5 years ago

        Thanks! Absolutely. Calling V code is as simple as calling C (V can emit C).

    • flavio81 5 years ago

      >I'm working on a language with a focus on simplicity and "only one way to do it":

      If I wanted a language with "only one way to do it", i'd use Brainfuck. Which, btw, is very easy to learn, well documented, and the same source code runs on many, many platforms.

  • JustSomeNobody 5 years ago

    I see what you're saying, but I kinda like the gets ":=" operator.

    • simondw 5 years ago

      But now there are two ways to do assignment. That's not very pythonic, is it?

      • msluyter 5 years ago

        You think that's bad? Check out:

            a = 17
            print("a=", a)
            print("a=" + str(a))
            print("a=%s" % a)
            print("a={}".format(a))
            print(f"a={a}") 
            # python 3.8 =>
            print(f"{a=}")
        
        So many ways to do it...

        But, if it sounds like I agree with you, I actually don't. I feel that the Zen of Python has taken on an almost religious level of veneration in people's minds, and leads to all sorts of unproductive debates. One person can latch onto "there should be one obvious way to do it" and another onto "practicality beats purity" and another onto "readability counts." Who's right? All can be. Or none. All could be applied to this particular case.

        The Zen of Python is just a set of rough heuristics, and no heuristic or principle in the field of software development applies 100% of the time, IMHO. <= except for this one ;)

        • HelloNurse 5 years ago

          > there should be one obvious way to do it

          In cases like this, different ways to do it (all equally good) are needed to get a good coverage of different tastes in obviousness and different nuances in the task.

          The point is not uniformity, but avoiding the unpleasant and convoluted workarounds caused by non-obviousness (thus making the language easy to use).

          String formatting is not trivial: there is the split (sometimes architectural, sometimes of taste, sometimes of emphasis) between concatenating string pieces, applying a format to objects, setting variable parts in templates, and other points of view; and there is a variety of different needs (cheap and convenient printing of data, dealing with special cases, complex templates...)

        • Erwin 5 years ago

          And there was also:

              print string.Template("a=$a").substitute(a=a)
      • marmada 5 years ago

        I never felt like there was only one way to do something in Python. Every Stack Overflow question has a multitude of answers ranging from imperative to functional style and with various benefits and drawbacks.

        Python is one of the least "only one way to do things" languages I've used. This even extends to its packaging system, where you can choose between virtualenv, pipenv, pyenv, etc. Same goes for the installation method too, do you want to install Python with Anaconda or use the default method?

        As for my personal take on this feature: I think it's really useful. When web-scraping in Python, I oftentimes had to do this:

          while True:
              html_element = scrape_element()
              if html_element:
                  break
              sleep(10)
        
        Now I can do this:

          while not html_element := scrape_element():
              sleep(10)
        • Erwin 5 years ago

          Prior to that you could use the special two-argument version of the `iter` function which makes it act completely different than the single argument version:

              for html_element in iter(scrape_element, None):
          
          this calls scrape_element() until it returns None, returning each value.
        • donio 5 years ago

          It used to be more or less true in the early days. For me the "one obvious way to do it" ship has sailed with list comprehensions which was introduced in 2.0 (released in 2000)

        • orf 5 years ago

          Packaging isn’t really anything to do with the language syntax, or the zen of Python. Any critiques on Python-the-language?

          And pyenv is just a version manager, like rbenv or nvm. I wouldn’t consider its existence confusing, not would I say being able to install something in more than 1 way has any relevance to the zen of Python!

          Should Python create some cross-platform Uber-installer so that there is only one download link?

          • marmada 5 years ago

            I don't see why the "zen of Python" shouldn't be applied to its tools too. Tools are part of the developer experience and few/none of the statements/guidelines in the zen of Python are exclusive to Python the programming language.

            Regardless of what pyenv, the rest of my comment about the complexity of Python's tooling still stands. There's too many choices. I also seen people use pyenv as an alternative to virtualenvs, which is something I have never seen with nvm.

            I don't understand why the Python community hasn't coalesced around a single solution to package management that has minimal complexity. It seems like pipenv is the solution, but there is controversy around it and it should have come several years ago. The fact that Python packages are installed globally by default is also pretty terrible, I much prefer it when applications bundle their dependencies. When I do `npm install --global`, the resulting program will always work, regardless of what other packages I have installed on my system.

            > Any critiques on Python-the-language?

            The point of my original comment was not to necessarily critique the Python programming language, rather it was to point out that adhering to the "zen of Python" is a lost cause because the language/development environment is not designed as a curated experience.

            And my original comment did make points about Python-the-language. I talked about how there's many ways to do a single task in Python. One of the responses to it even proved my point:

            "Prior to that you could use the special two-argument version of the `iter` function which makes it act completely different than the single argument version: <code sample>".

            That unfortunately demonstrates my point.

        • hexane360 5 years ago

          >Every Stack Overflow question has a multitude of answers ranging from imperative to functional style and with various benefits and drawbacks.

          This is one of the reasons I love Python. It's a great exercise to rewrite the same code imperative, recursive, with generators, with iterables, etc. Python is very good at supporting a wide range of programming styles.

      • Sohcahtoa82 5 years ago

        I see this criticism every time the walrus operator is brought up.

        You do know that this:

            x := 1
        
        Is going to be a syntax error, right? The walrus operator is not permitted in the case of a simple assignment statement. It's only in an expression.
        • Scarblac 5 years ago

          But it used to be that any expression on its own was a valid statement. Is that going to change?

          When is an expression allowed to have := in it, is

            (x := 1)
          
          on its own allowed?
          • n3k5 5 years ago

            For contexts where the walrus is not allowed, see [0]. You'll find that it's generally possible to circumvent the restriction by parenthesising the expression. So yes,

                (x := 1)
            
            is a valid (but poorly written) statement.

            But while there are now two ways of doing assignment, I wonder how often people will actually encounter situations where it's difficult to figure out which choice is better.

            [0] https://www.python.org/dev/peps/pep-0572/#exceptional-cases

          • Sohcahtoa82 5 years ago

            Allowed, yes. But the PEP that introduced walrus operators says not to do it.

            Every possible line of code has an alternate ugly way to write it. This isn't a valid criticism. Anyone who decides to start writing simple assignment statements like that deserves to be ridiculed for writing ugly code.

            • Scarblac 5 years ago

              Of course, and there's no reason to write such code.

              I just dislike that the simple syntax rule "any expression can be used as a statement" now has an exception.

              I haven't been able to think of scenarios where that might have consequences (code generation or refactoring tools?) but that doesn't say much as I'm not that smart.

              Edit: having looked at the cases that are disallowed, they remind me of generator expressions. Those are usually written with parens, that can optionally be omitted in some cases. := is the same except they can be omitted in so many cases that it's easier to list the cases where they can't.

              I think a generator expression used as a statement already requires the parens, even though they can be omitted e.g. as a single parameter of a function call. So that's probably ok then.

      • duckerude 5 years ago

        Not really, but neither are ugly nested if statements (Flat is better than nested, readability counts, etcetera). You need to make tradeoffs.

        Maybe it would have been better to only have a single := assignment operator to begin with. But it's a few decades too late for that.

        For what it's worth, := is for expressions only. Using it as a statement is a syntax error. So there won't be a lot of cases where both are equally elegant options.

      • nneonneo 5 years ago

        Regular = can only be used in statements. Walrus := can only be used in expressions. There's no overlap there. However, := does simplify certain expressions (like those nested if-else statements and the common "while chunk := read()" loop), which I think does justify its existence.

        • txcwpalpha 5 years ago

          This honestly makes it seem more confusing to me. The fact that there is now an operator that can only be used in certain statements just makes things more confusing. And if there really is no overlap, then why wasn't the "=" operator just extended to also work in expressions? "while chunk = read()" seems like it makes just as much sense without adding the confusion of another operator.

          • ericdevries 5 years ago

            One of the good things about not using the "=" operator is that you cannot accidentally turn a comparison into an assignment, a feature that is a common cause of errors in other languages that do support it. By adding a completely different character to the operator it is not very likely to cause bugs, compared to just forgetting to type that second =

            • bluecalm 5 years ago

              Is it really that common? I made this typo a few times in my life. It was corrected every time before the program actually run because the compiler warned me about it. I don't see how you can make this mistake if you're not aggressively trying (by turning off warnings for example).

              • ericdevries 5 years ago

                I guess it is not common, but by using the = operator you would not get the warning, and instead get unexpected behaviour.

          • dragonwriter 5 years ago

            > The fact that there is now an operator that can only be used in certain statements just makes things more confusing

            The new operator (like many Python operators) can only be used in expressions (statements can contain expressions, but expressions are not a subset of statements.)

            > The fact that there is now an operator that can only be used in certain statements just makes things more confusing

            Because the “=” operator is the thing that defines an assignment statement. Even if this could be resolved unambiguously for language parsers, so that “statement defining” and “within expression” uses didn't clash, it would be create potential readability difficulties for human reading. Keeping them separate makes the meaning of complicated assignment statements and assignment-including expressions more immediately visually clear.

            • txcwpalpha 5 years ago

              >it would be create potential readability difficulties for human reading

              I think the major argument (at least, the one I see most frequently) is that the walrus operator does create readability difficulties for humans, which is exactly why many people view it as non-pythonic. This is one of the few times I've seen someone argue that ":=" makes things more readable.

              • dragonwriter 5 years ago

                An argument against expression assignment is that it can create readability problems compared to separating the assignment from the expression in which the value is used. Even most supporters of the feature agree that this can be true in many cases and that it should be used judiciously.

                This is in no way contrary to the argument that the walrus operator improves readability of expression assignments compared to using the same operator that defines assignment statements.

      • nerdponx 5 years ago

        There are at least three ways to iterate over a list and create a new list as a result. That's not very pythonic, is it?

      • geofft 5 years ago

        The Zen of Python states:

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

        There are plenty of ways to do assignments. Walrus assignments are only the obvious way in certain cases, and in general there aren't other obvious ways. For testing and assigning the result of re.match, for instance, walrus assignments are clearly better than a temporary.

        I can think of lots of nonobvious ways to do assignments, like setattr(__module__...)

      • JustSomeNobody 5 years ago

        I can think of more than two ways to do a lot of things in Python. Besides the ":=" doesn't work exactly the same.

        Also, I can't bring myself to call it the walrus operator. Sorry, guys. I had a Pascal teacher ages ago who pronounced it "gets" and that has always stuck.

      • theplague42 5 years ago

        Assignment can be confusing already.

          >>> locals()['a'] = 1
          >>> a
          1
        
        If anything, the walrus operator allows for tightly-scoped assignment, which is good in my opinion.
        • ben509 5 years ago

          You don't even need the locals() function to get into trouble:

              x = [1, 2, 3, 4]
              def foo():
                  x[0] += 3  # Okay
              def bar():
                  x += [3]   # UnboundLocalError
              def qux():
                  x = [5, 6, 7, 8]  # Binds a new `x`.
          • zephyrfalcon 5 years ago

                def bar():
                    x += [3]   # UnboundLocalError
            
            This is an especially funky one. x.extend([3]) would be allowed. Presumably x += [3] is not because it expands to x = x + [3]... However, the += operator on lists works the same as extend(), i.e. it changes the list in-place.
            • ben509 5 years ago

              dis.dis(bar) shows:

                            0 LOAD_FAST                0 (x)
                            2 LOAD_CONST               1 (3)
                            4 INPLACE_ADD
                            6 STORE_FAST               0 (x)
                            8 LOAD_CONST               0 (None)
                           10 RETURN_VALUE
              
              So INPLACE_ADD and STORE_FAST are essentially doing x = x.__iadd__([3])
      • joshuamorton 5 years ago

        This isn't really true. There's one way to do assignment, `=`, and one way to do special assignment that also works as an expression, `:=`. You should always use `=` unless you *need `:=`.

  • tjpnz 5 years ago

    I don't think that philosophy was ever truly embraced to begin with. If you want evidence of that try reading the standard library (the older the better) and then try running the code through a linter.

  • chc 5 years ago

    The idea that str.format produced simpler or more readable code than f-strings is contrary to the experience of most Python users I know. Similarly, the contortions we have to go through in order to work around the lack of assignment expressions are anything but readable.

    I do agree that Python is moving further and further away from the only-one-way-to-do-it ethos, but on the other hand, Python has always emphasized practicality over principles.

  • pippy 5 years ago

    This is what happens when you lose a BDFL. While things become more "democratic", you lose the vision and start trying to make everyone happy.

    • mixmastamyk 5 years ago

      Walrus operator is the direct result of the BDFL pushing it over significant objection.

    • dlbucci 5 years ago

      Well, there were 4 versions released since 3.3 that still had a BDFL, so I dunno if that's the issue, yet.

  • hetman 5 years ago

    I'm someone who loves the new features even though I don't think they're "pythonic" in the classical meaning of this term. That makes me think that being pythonic at it's most base level is actually about making it easier to reason about your code... and on that count I have found most of the new features have really helped.

  • unethical_ban 5 years ago

    You can write very Python2.7 looking code with Python3. I don't think many syntax changes/deprecations have occurred (I know some have).

    • themeiguoren 5 years ago

      Yep, I did a 2to3 conversion recently and it got the whole project 95% of the way there. A 3to2 would be in theory almost as simple to do for most projects.

  • l0b0 5 years ago

    My first though was the same as the snarky sibling comment, but after reading TFA I realized these are all features I've used in other languages and detest. The walrus operator an complex string formatting are both character-pinching anti-maintainability features.

raymondh 5 years ago

To me, the headline feature for Python 3.8 is shared memory for multiprocessing (contributed by Davin Potts).

Some kinds of data can be passed back and forth between processes with near zero overhead (no pickling, sockets, or unpickling).

This significantly improves Python's story for taking advantage of multiple cores.

  • acqq 5 years ago

    For us who didn't follow:

    "multiprocessing.shared_memory — Provides shared memory for direct access across processes"

    https://docs.python.org/3.9/library/multiprocessing.shared_m...

    And it has the example which "demonstrates a practical use of the SharedMemory class with NumPy arrays, accessing the same numpy.ndarray from two distinct Python shells."

    Also, SharedMemory

    "Creates a new shared memory block or attaches to an existing shared memory block. Each shared memory block is assigned a unique name. In this way, one process can create a shared memory block with a particular name and a different process can attach to that same shared memory block using that same name.

    As a resource for sharing data across processes, shared memory blocks may outlive the original process that created them. When one process no longer needs access to a shared memory block that might still be needed by other processes, the close() method should be called. When a shared memory block is no longer needed by any process, the unlink() method should be called to ensure proper cleanup."

    Really nice.

  • quietbritishjim 5 years ago

    It looks like this will make efficient data transfer much more convenient, but it's worth noting this had always been possible with some manual effort. Python has had `mmap` support at least as long ago as Python 2.7, which works fine for zero-overhead transfer of data.

    With mmap you have to specify a file name (actually a file number), but so long as you set the length to zero before you close it there's no reason any data would get written to disk. On Unix you can even unlink the file before you start writing it if you wish, or create it with the tempfile module and never give it a file name at all (although this makes it harder to open in other processes as they can't then just mmap by file name). The mmap object satisfies the buffer protocol so you can create numpy arrays that directly reference the bytes in it. The memory-mapped data can be shared between processes regardless of whether they use the multiprocessing module or even whether they're all written in Python.

    https://docs.python.org/3.7/library/mmap.html

    • mncharity 5 years ago

      Also on linux is sysv_ipc.SharedMemory.

  • agent008t 5 years ago

    Isn't that already the case?

    I thought that when you use multiprocessing in Python, a new process gets forked, and while each new process has separate virtual memory, that virtual memory points to the same physical location until the process tries to write to it (i.e. copy-on-write)?

    • jashmatthews 5 years ago

      That's true but running VMs mutate their heaps, both managed and malloced. CoW also only works from parent to child. You can't share mutable memory this way.

      Empty space in internal pages gets used allocating new objects, refence counts updated or GC flags get flipped etc, and it just takes one write in each 4kb page to trigger a whole page copy.

      It doesn't take long before a busy web worker etc will cause a huge chunk of the memory to be copied into the child.

      There are definitely ways to make it much more effective like this work by Instagram that went into Python 3.7: https://instagram-engineering.com/copy-on-write-friendly-pyt...

    • amelius 5 years ago

      Yes, the problem is sharing data between parent and child after the parent process has been forked.

    • paulddraper 5 years ago

      Yes, sharing pre-fork data is as old as fork().

      Sharing post-fork data is where it gets interesting.

    • sametmax 5 years ago

      If you have 4 cores, you may want to spaw 4 children, then share stuff between them. Not just top-down.

      E.G: live settings, cached values, white/black lists, etc

  • amelius 5 years ago

    > no pickling, sockets, or unpickling

    But still copying?

    If not, then how does it interoperate with garbage collection?

  • aportnoy 5 years ago

    I’ve been waiting for this for a very long time. Thank you for mentioning this.

    Would this work with e.g. large NumPy arrays?

    (and this is Raymond Hettinger himself, wow)

    • solarist 5 years ago

      An alternative you may want is Dask.

      • aportnoy 5 years ago

        Dask doesn’t support shared memory without pickling because Python doesn’t.

  • aidos 5 years ago

    Oh no way. That has huge potential. What are the limitations?

londons_explore 5 years ago

I long for a language which has a basic featureset, and then "freezes", and no longer adds any more language features.

You may continue working on the standard library, optimizing, etc. Just no new language features.

In my opinion, someone should be able to learn all of a language in a few days, including every corner case and oddity, and then understand any code.

If new language features get added over time, eventually you get to the case where there are obscure features everyone has to look up every time they use them.

  • vindarel 5 years ago

    Common Lisp seems to tick the boxes. The syntax is stable and it doesn't change. New syntax can be added through extensions (pattern matching, string interpolation, etc). The language is stable, meaning code written in pure CL still runs 20 years later. Then there are de-facto standard libraries (bordeaux-threads, lparallel,…) and other libraries. Implementations continue to be optimized (SBCL, CCL) and to develop core features (package-local-nicknames) and new implementations arise (Clasp, CL on LLVM, notably for bioinformatics). It's been rough at the beginning but a joy so far.

    https://github.com/CodyReichert/awesome-cl

    • nine_k 5 years ago

      The "very compact, never changing" language will end up not quite expressive, thus prone to boilerplate; look at Go.

      Lisps avoid this by building abstractions from the same material as the language itself. Basically no other language family has this property, though JavaScript and Kotlin, via different mechanisms, achieve something similar.

      • agumonkey 5 years ago

        I like to think that lisp is its own fixed point.

  • DonHopkins 5 years ago

    The Turing Machine programming language specification has been frozen for a long time, and it's easy to learn in a few days.

    So has John von Neumann's 29 state cellular automata!

    https://en.wikipedia.org/wiki/Von_Neumann_cellular_automaton

    https://en.wikipedia.org/wiki/Von_Neumann_universal_construc...

    (Actually there was a non-standard extension developed in 1995 to make signal crossing and other things easier, but other than that, it's a pretty stable programming language.)

    >Renato Nobili and Umberto Pesavento published the first fully implemented self-reproducing cellular automaton in 1995, nearly fifty years after von Neumann's work. They used a 32-state cellular automaton instead of von Neumann's original 29-state specification, extending it to allow for easier signal-crossing, explicit memory function and a more compact design. They also published an implementation of a general constructor within the original 29-state CA but not one capable of complete replication - the configuration cannot duplicate its tape, nor can it trigger its offspring; the configuration can only construct.

  • mr_crankypants 5 years ago

    Such languages exist. Ones that come to mind offhand are: Standard ML, FORTH, Pascal, Prolog.

    All of which are ones that I once thought were quite enjoyable to work in, and still think are well worth taking some time to learn. But I submit that the fact that none of them have really stood the test of time is, at the very least, highly suggestive. Perhaps we don't yet know all there is to know about what kinds of programming language constructs provide the best tooling for writing clean, readable, maintainable code, and languages that want to try and remain relevant will have to change with the times. Even Fortran gets an update every 5-10 years.

    I also submit that, when you've got a multi-statement idiom that happens just all the time, there is value in pushing it into the language. That can actually be a bulwark against TMTOWTDI, because you've taken an idiom that everyone wants to put their own special spin on, or that they can occasionally goof up on, and turned it into something that the compiler can help you with. Java's try-with-resources is a great example of this, as are C#'s auto-properties. Both took a big swath of common bugs and virtually eliminated them from the codebases of people who were willing to adopt a new feature.

    • zephyrfalcon 5 years ago

      Prolog has an ISO standard... I am not sure if it's still evolving, but specific Prolog implementations can and often do add their own non-standard extensions. For example, SWI-Prolog added dictionaries and a non-standard (but very useful) string type in version 7.

      That said, it is nice that I can take a Prolog text from the 1980s or 1990s and find that almost all of the code still works, with minor or no modifications...

  • mbo 5 years ago

    Elixir?

    From the v1.9 release just a few weeks ago: https://elixir-lang.org/blog/2019/06/24/elixir-v1-9-0-releas...

    > As mentioned earlier, releases was the last planned feature for Elixir. We don’t have any major user-facing feature in the works nor planned. I know for certain some will consider this fact the most excing part of this announcement!

    > Of course, it does not mean that v1.9 is the last Elixir version. We will continue shipping new releases every 6 months with enhancements, bug fixes and improvements.

    • elgenie 5 years ago

      That's just an announcement that they reached the end of the list of user-facing syntax changes on their roadmap.

    • scribu 5 years ago

      Interesting!

      I imagine churn will still happen, except it will be in the library/framework ecosystem around the language (think JavaScript fatigue).

      • _asummers 5 years ago

        Most Elixir projects have very few dependencies because the Elixir and Erlang stdlibs are very batteries included. You don't typically reach for a dependency unless you need most of its features. Often you will reimplement the parts you need in your own code, except where it's reasonably complicated (pooling, DB connections, ORMs, web frameworks) or tricky to get right (security, password hashing, paxos).

  • poiuyt098 5 years ago

    Brainfuck has been extremely stable. You can learn every operator in minutes.

  • nerdponx 5 years ago

    someone should be able to learn all of a language in a few days, including every corner case and oddity, and then understand any code.

    Why should this be true for every language? Certainly we should have languages like this. But not every language needs to be like this.

    • esfandia 5 years ago

      Well, maybe not for every language, but probably for a language where simplicity has been a major feature.

      • pmontra 5 years ago

        I started using Python seriously only three years ago after 30 years of other languages and I didn't find it very simple. Maybe the core of the language is simple but the standard library and many other important modules can be very complicated. Among similar languages Ruby and JavaScript are far simpler.

        • londons_explore 5 years ago

          JavaScript used to be simple... But Promises, closures, prototype chains, and npm/modules/minification/webpack has added a massive amount of complexity to being able to just read and understand a bit of code.

        • goatlover 5 years ago

          Javascript isn't simple any longer. And I'm not sure Ruby is that simple, not once you dig into the advanced features.

    • arkaic 5 years ago

      Verrrrrrry few languages in common use are like this.

  • fatbird 5 years ago

    All you're doing then is moving the evolution of the language into the common libraries, community conventions, and tooling. Think of JavaScript before ES2015: it had stayed almost unchanged for more than a decade, and as a result, knowing JavaScript meant knowing JS and jQuery, prototype, underscore, various promise libraries, AMD/commonjs/require based module systems, followed by an explosion of "transpiled to vanilla JS" languages like coffeescript. The same happened with C decades earlier: while the core language in K&R C was small and understandable, you really weren't coding C unless you had a pile of libraries and approaches and compiler-specific macros and such.

    Python, judged against JS, is almost sedate in its evolution.

    It would be nice if a combination of language, libraries, and coding orthodoxy remained stable for more than a few years, but that's just not the technology landscape in which we work. Thanks, Internet.

    • elgenie 5 years ago

      It's apples and oranges.

      Python was explicitly designed and had a dedicated BDFL for the vast majority of its nearly 30 year history functioning as a standards body.

      JS, on the other hand, was hacked together in a week in the mid-90s and then the baseline implementation that could be relied on was emergent behavior at best, anarchy at worst for 15 years.

      • fatbird 5 years ago

        Agreed, but the anarchy of JS was a result of a dead standards process between the major vendors that resulted in de facto freeze. The anarchy is direct result of a stewardship body not evolving the language to meet evolving needs.

  • jnwatson 5 years ago

    The only frozen languages are the ones nobody uses except for play or academic purposes.

    As soon as people start using a language, they see ways of improving it.

    It isn't unlike spoken languages. Go learn Esperanto if you want to learn something that doesn't change.

    • BillChapman 5 years ago

      Esperanto does change, in that new items of vocabulary are introduced from time to time. For example, 'mojosa', the word for 'cool' is only about thirty years old.

  • colechristensen 5 years ago

    This is why a lot of scientific code still uses fortran, code written several decades ago still compiles and has the same output.

    How long has the code which was transitioned to python lasted?

    • airstrike 5 years ago

      > How long has the code which was transitioned to python lasted?

      A long time. 2to3 was good for ~90% of my code, at least

      • colechristensen 5 years ago

        Good for 90% of your code is not equivalent to getting precisely the same results from unmodified code written in the 80s.

        • mixmastamyk 5 years ago

          More likely to mean 90% of projects, not 90% of each file, which would mean that every one was broken.

      • hdfbdtbcdg 5 years ago

        We will review that statement in 30 years!

        • yxhuvud 5 years ago

          Likely, we will review that statement in 2038 at the latest.

    • tjalfi 5 years ago

      I have compiled Fortran programs from the 70s on modern platforms without changing a line. The compiler, OS, and CPU architecture had all disappeared but the programs still worked correctly.

    • yxhuvud 5 years ago

      Fortran has added a whole lot of features over time though.

      • TheRealKing 5 years ago

        but you can still compile F66 with Intel Fortran compiler 2020 (and other compilers as well)

    • stefco_ 5 years ago

      This isn't that good of a metric for code utility. Sure, very-long-lived code probably solved the problem well (though it can also just be a first-mover kind of thing), but a lot of code is written to solve specific problems in a way that's not worth generalizing.

      I write a lot of python for astrophysics. It has plenty of shortcomings, and much of what's written will not be useful 10 years from now due to changing APIs, architectures, etc., but that's partly by design: most of the problems I work on really are not suited to a hyper-optimized domain-specific languages like FORTRAN. We're actively figuring out what works best in the space, and shortcomings of python be damned, it's reasonably expressive while being adequately stable.

      C/FORTRAN stability sounds fine and good until you want to solve a non-mathematical problem with your code or extend the old code in some non-trivial way. Humans haven't changed mathematical notations in centuries (since they've mostly proven efficient for their problem space), but even those don't always work well in adjacent math topics. The bra-ket notation of quantum mechanics, <a|b>, was a nice shorthand for representing quantum states and their linear products; Feynman diagrams are laughably simple pictograms of horrid integrals. I would say that those changes in notation reflected exciting developments that turned out to persist; so it is with programming languages, where notations/syntaxes that capture the problem space well become persistent features of future languages. Now, that doesn't mean you need to code in an "experimental" language, but if a new-ish problem hasn't been addressed well in more stable languages, you're probably better off going where the language/library devs are trying to address it. If you want your code to run in 40 years, use C/FORTRAN and write incremental improvements to fundamental algorithm implementations. If you want to solve problems right now that those langs are ill-suited to, though, then who cares how long the language specs (or your own code) last as long as they're stable enough to minimize breaking changes/maintenance? This applies to every non-ossified language: the hyper-long-term survival of the code is not the metric you should use (in most cases) when deciding how to write your code.

      My point is just that short code lifetimes can be perfectly fine; they can even be markers of extreme innovation. This applies to fast-changing stuff like Julia and Rust (which I don't use for work because they're changing too quickly, and maintenance burdens are hence too high). But some of their innovative features will stand the test of time, and I'll either end up using them in future versions of older languages, or I'll end up using the exciting new languages when they've matured a bit.

      • TheRealKing 5 years ago

        by the way, three-decades has gone since FORTRAN became Fortran.

  • hu3 5 years ago

    From what I've seen, Go is the closest we have for mainstream language resistant to change.

    • zubspace 5 years ago

      Recently the Go team decided not to add the try-keyword to the language. I'm not a Go programmer and was a bit stumped by the decision until I saw a talk of Rob Pike regarding the fundamental principle of Go to stick to simplicity first. [1]

      One of the takeaways is, that most languages and their features converge to a point, where each language contains all the features of the other languages. C++, Java and C# are primary examples. At the same time complexity increases.

      Go is different, because of the simplicity first rule. It easens the burden on the programmer and on the maintainer. I think python would definitely profit from such a mindset.

      [1] https://www.youtube.com/watch?v=rFejpH_tAHM

  • orangecat 5 years ago

    In my opinion, someone should be able to learn all of a language in a few days, including every corner case and oddity, and then understand any code.

    "Understanding" what each individual line means is very different from understanding the code. There are always higher level concepts you need to recognize, and it's often better for languages to support those concepts directly rather than requiring developers to constantly reimplement them. Consider a Java class where you have to check dozens of lines of accessors and equals and hashCode to verify that it's an immutable value object, compared to "data class" in Kotlin or @dataclass in Python.

    • toolslive 5 years ago

      Sometimes a language introduces a concept that's new to you. Then you need way more time. For example, monads : I understood it (the concept) rather quickly, but it took a few weeks to get it down so I could benefit from it.

  • orwin 5 years ago

    Try C maybe? It is still updated, but only really minor tweaks for optimisation.

    Also Common lisp specs never changed since the 90s and is still usefull as a "quick and dirty" language, with few basic knowledge required. But the "basic feature set" can make everything, so the "understand any code" is not really respected. Maybe Clojure is easier to understand (and also has a more limited base feature set, with no CLOS).

    • kazinator 5 years ago

      C compilers like GCC and Clang have dialect selection options that work; if you pick -std=c90, you can write C like it's 1990.

  • baq 5 years ago

    remember the gang of four book? such books happen when the language is incapable of expressing ideas concisely. complexity gets pushed to libraries which you have to understand anyway. i'd rather have syntax for the visitor pattern or whatever else is there.

  • markrages 5 years ago

    Python 2.7 is not far from that language.

    • tomkat0789 5 years ago

      What's stopping people from forking the language at python 2.7? Let the pythonistas add whatever feature they feel like while people who need stability use "Fortran python" or whatever.

      • rtpg 5 years ago

        Probably most of the people who like writing language interpreters understood that Python 3 fixed a lot of mistakes, so it would be funner to work on.

        Though I'm surprised nobody really wrote a transitional fork (six gets you a lot of the way but "Python 2.8 which has _just_ the str/bytes change" would have been useful).

        Ultimately Python 2 isn't a better language, it's just the language everyone's code was in...

      • jakeogh 5 years ago

        In my fantasy-py language, there is no "str", base types would be explicit. unicode() bytes(). "something" could have an implicit u"". Composite types could be explicit. If I want a set of int's, I can use mypy now to s1: t.Set[int] = set(), but that's just linting.

      • fractalb 5 years ago

        > What's stopping people from forking the language at python 2.7?

        If you don't want to change/add something to the language, then why fork it?. You can just continue using it as it is!

        • Volt 5 years ago

          The implementation needs to be maintained.

      • newen 5 years ago

        I truly wish this would become a thing. It's really frustrating having to update my installed packages and my code for some stupid change the language designers thought is sooo worth it. Just stabilize the bloody thing so I can do some work. Updating code so it meshes with the "latest and greatest" is _not real work_.

        • orf 5 years ago

          Fixing the entirely broken string/bytes mess up in Python 2 was worth it by itself. For bonus points old style classes went away, and the language got a significant speed boost. And now it’s not going to die a slow death, choking on the past poor decisions it’s burdened with.

          Trivializing that by suggesting it was some offhand, unneeded solution to a problem that some dreamy “language designer” thought up is at best completely and utterly ignorant.

          Also maintenance, in all forms, is work. That does involve updating your systems from time to time.

          • Redoubts 5 years ago

            > and the language got a significant speed boost.

            I have not seen a clear win in real benchmarks. 3 was slower for the longest time, and nowadays it seems head to head depending on the project.

          • newen 5 years ago

            Maybe it's work if you get paid by lines of code and JIRA tickets but programming is just a tool for me to my real work done. So I would like to spend as little time programming as I possibly can.

            • orf 5 years ago

              Nobody here gets paid per Jira ticket or line of code.

              Sure, if you don’t program and just write ad-hoc (unmaintainable?) scripts then the transition is annoying. But it’s also not required. Don’t re-write your scripts, you can always ensure that Python 2 is present.

              But if you’re maintaining a project that uses the wider ecosystem, then you are at the mercy of that ecosystem. And, at the time of the decision to make Python 3, that ecosystem was saying “Python 2 has a lot of horrible legacy decisions that make it harder than it should be to write good code”.

        • dannyfraser 5 years ago

          Containers or environment management solve this problem quite easily. All of my major projects have a conda environment alongside them, and I expect I'll be shifting things over to Docker containers as my org starts shifting things to the cloud.

  • plopz 5 years ago

    Isn't that what C is?

  • alexhutcheson 5 years ago

    Lua is pretty close, and pretty close to Python in terms of style and strengths.

    Edit: I actually forgot about the split between LuaJIT (which hasn’t changed since Lua 5.1), and the PUC Lua implementation, which has continued to evolve. I was thinking of the LuaJIT version.

  • linsomniac 5 years ago

    I'm in operations and I've spent much of my career writing code for the Python that worked on the oldest LTS release in my fleet, and for a very long time that was Python 1.5...

    I was really happy, in some ways, when Python 2 was announced as getting no new releases and Python 3 wasn't ready, because it allowed a kind of unification of everyone on Python 2.7.

    Now we're back on the treadmill of chasing the latest and greatest. I was kind of annoyed when I found I couldn't run Black to format my code because it required a slightly newer Python than I had. But... f strings and walrus are kind of worth it.

  • owaislone 5 years ago

    That's what Go has been so far but it might see some changes soon after being "frozen" for ~10 years.

  • diminoten 5 years ago

    Why can't you do this with Python? No one said you had to use any of these new features...

    Though to me that's like saying, "I want this river to stop flowing" or "I'd prefer if the seasons didn't change."

  • dwaltrip 5 years ago

    All human languages change over time. It is the nature of language.

  • chewxy 5 years ago

    Go? I moved a lot of my datascience and machine learning process to Go. Only thing really left in Python land is EDA

  • Areading314 5 years ago

    Absolutely agree. How many times have you heard "that was true until Python 3.4 but now is no longer an issue" or "that expression is illegal for all Pythons below 3.3", and so on. Not to mention the (ongoing) Python 2->3 debacle.

    • TomBombadildoze 5 years ago

      > Not to mention the (ongoing) Python 2->3 debacle.

      When will this talking point die? It's not "ongoing". There's an overwhelming majority who have adopted Python 3 and a small population of laggards.

      • Redoubts 5 years ago

        > There's an overwhelming majority who have adopted Python 3 and a small population of laggards.

        That small population includes every BigCo with a large python codebase.

    • orf 5 years ago

      Who cares about syntax that doesn’t work in old, dead versions of Python 3? 3.5 and above is all that matters.

  • coleifer 5 years ago

    Lua is a great small language.

  • locoman88 5 years ago

    Fully agree. If we continue with this madness in five years Python will become indistinguishable from the Python I learnt 10 years ago.

    Seems the Golang people have much cooler heads. Time to push for Golang at my workplace

  • dingo_bat 5 years ago

    You're talking about C.

stakhanov 5 years ago

Speaking as someone who has written Python code almost every day for the last 16 years of my life: I'm not happy about this.

Some of this stuff seems to me like it's opening the doors for some antipatterns that I'm consistently frustrated about when working with Perl code (that I didn't write myself). I had always been quite happy about the fact that Python didn't have language features to blur the lines between what's code vs what's string literals and what's a statement vs what's an expression.

  • sametmax 5 years ago

    F-strings have appeared 2 versions ago. All in all, the feedback we have has been overwhelmingly positive, including on maintenance and readability.

    • theplague42 5 years ago

      I second this. F-strings make string formatting so much more concise. I'm excited about the walrus operator for the same reason.

      • mr_crankypants 5 years ago

        Not just more concise; less error prone.

        A reasonably large number of the bugs I encounter relate to the order or number of formatting arguments not matching the slots in the format string. It's pretty hard to make that kind of mistake with an fstring.

      • agumonkey 5 years ago

        f-strings allow mutation ?

        mutation is tricky, a whole field of programming language research is built on avoiding mutation

    • sleavey 5 years ago

      I love f-strings. I just wish tools like pylint would shut up when I pass f-strings to the logging module. I as the developer understand and accept the extra nanosecond of processor time to parse the string that might not be logged anywhere!

      • MapleWalnut 5 years ago

        It's not just performance!

        Using percent formatting is superior in many ways:

        - errors that occur in formatting a message will be logged instead of raising an exception into your application

        - error reporting services like Sentry can properly aggregate events

        - interpolation won't occur if you don't have the logging level enabled

        - it's recommend by the Python docs: https://docs.python.org/3/howto/logging-cookbook.html#use-of...

      • orf 5 years ago

        It's not always a nanosecond, some string representations can take a while to create. In poorly coded Django models they could involve a trip to the database.

        • mixmastamyk 5 years ago

              if logger.isEnabledFor(logging.DEBUG):
                  logger.debug(f'{expensive_func()}')
          • orf 5 years ago

            I hope that’s a joke, because that is a verbose and ridiculous way of duplicating the work that the logging module does, while also making the code less readable and maintainable!

            • mixmastamyk 5 years ago

              That’s how you defer an expensive function. The fstring part is the joke.

      • sametmax 5 years ago

        Disable it in pylintrc. Pylint is unusable without a good config file anyway.

        • sleavey 5 years ago

          Ideally the defaults should be sensible. I have found they mostly are, except the f-string one.

          • sametmax 5 years ago

            For something as finely tuned as pylint, my sensible default and your would never be the same.

            I don't want it to scream on a missing docstring for every single thing. I do want to be able to use a, b and x as variables. No, this root var is not a constant, don't ask me for uppercase. Etc.

          • baq 5 years ago

            on the contrary, i've seen code slow down by 50% due to a log.debug() that wasn't even emitted in prod. should've seen my face when i saw the pyspy flamechart.

          • emidln 5 years ago

            pylint still sucks at partial function definitions. It wants to name anything that exists in the module scope that isn't an explicit function definition with CAPS_LOCK_MODE.

                $ pylint pylint_sucks_at_partials.py 
                ************* Module pylint_sucks_at_partials
                pylint_sucks_at_partials.py:7:0: C0103: Constant name 
                "add5" doesn't conform to UPPER_CASE naming style 
                (invalid-name)
            
            The program in question:

                #!/usr/bin/env python
                """ proving pylint still sucks at partials """
                from functools import partial
                from operator import add
                
                
                add5 = partial(add, 5)
                
                
                if __name__ == '__main__':
                    import sys
                    print(add5(int(sys.argv[1])))
    • pmontra 5 years ago

      F-string are great and should have been in the language since the beginning. Many other languages had with their own version of them since version 0. What I don't understand is why Python needs a special string type when other languages can interpolate normal strings (Ruby, Elixir, JavaScript.)

      • duckerude 5 years ago

        f-strings need a prefix so old strings can keep working the same way.

        If `print("{x}")` printed "{x}" in Python 3.5, it shouldn't print something else in a newer version. But `print(f"{x}")` was a syntax error before f-strings, so no code is broken by giving it a meaning.

        JavaScript can't interpolate ordinary strings either, for the same reason. You need to use backticks (``).

        • pmontra 5 years ago

          You're correct about JavaScript. I forgot about the backticks.

          Thank you for the explanation of the f-strings. I'm pretty sure that migrating old strings to "\{x\}" could be automated but we can't force everybody to migrate their code. There is probably no other way than the one they followed.

          • duckerude 5 years ago

            "\{x\}" includes the backslashes into the string literally. So even if that worked for f-strings it would change the meaning for older Python versions. Requiring people to update common old code is also just something to avoid unless necessary.

            The correct way to escape braces in f-strings is with double braces, so f"{{x}}". This is consistent with the way str.format works. f-string syntax is very similar to str.format syntax in general.

          • Dylan16807 5 years ago

            It's also just safer. You want your default string type to have as few gotchas about what can be put in it as possible.

      • mixmastamyk 5 years ago

        Shells do it with "" and ''. Unfortunately Py and Js decided to allow both for regular strings, so there is not such an easy way to delineate them.

      • sametmax 5 years ago

        Because explicit is better than implicit.

    • stakhanov 5 years ago

      ...but every addition to make them more powerful and feature-rich is one more step in the direction of blurring the lines between what's code and what isn't, since more and more things that are supposed to be code will be expressed in ways that aren't code at all but fed to an interpreter inside the interpreter. And with every release, the language specification that I'm having to hold in my head when dealing with other people's code grows more and more complex while the cost-benefit calculation around the additional complexity shows diminishing returns.

      It kind of goes to the question: When is a language "finished"?

      • baq 5 years ago

        there's a difference between stability and stagnation and IMHO Python gets it.

        finished is dead, to put it less mildly.

  • hk__2 5 years ago

    As someone who has written Python code almost every day for both professional and personal projects for a few years: I’m really happy about these assignment expressions. I wish Python would have more expressions and fewer statements, like functional languages.

  • duckerude 5 years ago

    Do you have an example of bad code you'd expect people to use assignment expressions and f-strings for?

    I don't think I've come across any f-string abuse in the wild so far, and my tentative impression is that there's a few patterns that are improved by assignment expressions and little temptation to use them for evil.

    It helps that the iteration protocol is deeply ingrained in the language. A lot of code that could use assignment expressions in principle already has a for loop as the equally compact established idiom.

  • ashton314 5 years ago

    Many languages don't distinguish between statements and expressions—in some languages, this is because everything is an expression! I'm most familiar with these kinds of languages.

    I'm not familiar much with Python, beyond a little I wrote in my linear algebra class. How much does the statement/literal distinction matter to readability? What does that do for the language?

    • stakhanov 5 years ago

      The philosophy that most of Python's language design is based on is that for everything you want to do, there should be one and only one obvious way to do it.

      The first part of the statement (at least one obvious way to do it) goes to gaining a lot of expressive power from having learned only a subset of the language specification corresponding to the most important concepts. So you invest only a small amount of time in wrapping your head around only the most important/basic language concepts and immediately gain the power that you can take any thought and express it in the language and end up not just with some way of doing it, but with the right/preferred way of doing it.

      The second part of the statement (at most one obvious way to do it) makes it easy to induce the principles behind the language from reading the code. If you take a problem like "iterate through a list of strings, and print each one", and it always always always takes shape in code by writing "for line in lst: print( line )" it means that, if it's an important pattern, then a langauge learner will get exposed to this pattern early and often when they start working with the language, so has a chance to quickly induce what the concept is and easily/quickly memorize it due to all the repetition. -- Perl shows how not to do it, where there are about a dozen ways of doing this that all end up capable of being expressed in a line or two. -- Therefore, trying to learn Perl by working with a codebase that a dozen people have had their hands on, each one preferring a different variation, makes it difficult to learn the language, because you will now need to know all 12 variations to be able to read Perl reliably, and you will only see each one 1/12th as often making it harder to memorize.

      • uryga 5 years ago

        > "iterate through a list of strings, and print each one"

          print(*lst, sep='\n')
        
        :)
        • stakhanov 5 years ago

          That's exactly what I'm talking about. A REAL python programmer would immediately recognize that to be the bullshit way that someone would do it, if proving what a f*ing master they are were more important to them than clarity.

          • uryga 5 years ago

            i do it when i'm in a REPL and want to minimize typing, but probably wouldn't put it in an actual program... so i guess we mostly agree

    • nerdponx 5 years ago

      The only reason I can imagine being opposed to it is fear that hordes of bad programmers will descend on the language and litter the ecosystem with unreadable golfed garbage.

      I obviously don't want that. I don't think anybody wants that. But I also don't think that's going to happen as a result of the recent changes in the language. If anything, I feel like the average code quality in the wild has gone up.

      • yxhuvud 5 years ago

        Python being the start language for newbies these days, you already have the hordes of bad programmers. Everyone is bad when they start out, after all.

    • ezrast 5 years ago

      It's natural for some operations to be used only for their side effects, and for those a return value is just noise. What does a while loop evaluate to in your favorite language? Are there any circumstances where you'd want to assign one to a variable? What do you lose by making that a parser error?

      • uryga 5 years ago

        > What does a while loop evaluate to in your favorite language?

        depends on what you want! for example this Haskell package¹ defines three versions of while:

          -- collect the result of each iteration into a list
          whileM :: Monad m => m Bool -> m a -> m [a]
        
          -- combine the result of each iteration together into a final result
          whileM' :: (Monad m, MonadPlus f) => m Bool -> m a -> m (f a)
          
          -- drop the results and return `()`
          whileM_ :: Monad m => m Bool -> m a -> m ()
        
        by convention, the ones ending in an underscore (`forM_`, `whileM_`, `sequence_` etc) drop their results, i.e. are only used for their side-effects.

        ¹ http://hackage.haskell.org/package/monad-loops-0.4.3/docs/Co...

  • keymone 5 years ago

    > what's a statement vs what's an expression

    never understood the need for this. why do you even need statements?

    if there's one thing that annoys me in python it's that it has statements. worst programming language feature ever.

stefco_ 5 years ago

There's a lot of talk in this thread about Python going down-hill and becoming less obvious/simple. I rather like modern python, but I agree that some features (like async/await, whose implementation fractures functions and libraries into two colors [0]) seem like downgrades in "Pythonicity".

That said, I think some things have unquestionably gotten more "Pythonic" with time, and the := operator is one of those. In contrast, this early Python feature (mentioned in an article [1] linked in the main one) strikes me as almost comically unfriendly to new programmers:

> Python vowed to solve [the problem of accidentally assigning instead of comparing variables] in a different way. The original Python had a single "=" for both assignment and equality testing, as Tim Peters recently reminded him, but it used a different syntactic distinction to ensure that the C problem could not occur.

If you're just learning to program and know nothing about the distinction between an expression and a statement, this is about as confusing as shell expansion (another context-dependent syntax). It's way too clever to be Pythonic. The new syntax, though it adds an extra symbol to learn, is at least 100% explicit.

I'll add that := fixes something I truly hate: the lack of `do until` in Python, which strikes me as deeply un-Pythonic. Am I supposed to break out of `while True`? Am I supposed to set the variable before and at the tail of the loop (a great way to add subtle typos that will cause errors)? I think it also introduces a slippery slope to be encouraged to repeat yourself: if assigning the loop variable happens twice, you might decide to do something funny the 2:Nth time to avoid writing another loop, and that subtlety in loop variable assignment can be very easy to miss when reading code. There is no general solution I've seen to this prior to :=. Now, you can write something like `while line := f.readline()` and avoid repetition. I'm very happy to see this.

[0] https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...

[1] https://lwn.net/Articles/757713/

[edit] fixed typos

  • Asooka 5 years ago

    You are supposed to write

        for x in iter(f.readline, ""):
    
    Or if you don't know what readline will return you can wrap it in your own lambda:

        for x in iter(lambda:f.readline() or None, None):
    
    There is a lot you can do with iter to write the kind of loops you want but it's not well known for some reason. It's a very basic part of the language people seem to overlook. Walrus does however let you write the slightly more useful

        while predicate(x:=whatever()):
    
    Which doesn't decompose easily into iter form.
    • stefco_ 5 years ago

      This is a good solution! I don't directly use `iter` very often so I only remember it's simplicity part of the time. Sadly, this is not the idiom I see in most places.

      I will say, though, that I was not comfortable using iterators when I first learned python; walrus strikes me as easier to grok for a novice (one of the ostensible Python target demographics) than iter. I'll bet this is why this simple form is not idiomatic (though you're right, it should be).

  • owlowlowls 5 years ago

    >I'll add that := fixes something I truly hate: the lack of `do until` in Python, which strikes me as deeply un-Pythonic. Am I supposed to break out of `while True`? Am I supposed to set the variable before and at the tail of the loop (a great way to add subtle typos that won't cause errors)?

    This is relevant to what I've been doing in OpenCV with reading frames from videos! In tutorial examples on the web, you'll see exactly the sort of pattern that's outlined in the PEP 572 article.

    >line = f.readline()

    >while line:

    > ... # process line

    > line = f.readline()

    Just, replace readline() with readframe() and the like. So many off-by-one errors figuring out when exactly to break.

    • Aramgutang 5 years ago

      That example can also be tackled with Python's little-known feature of calling the built-in `iter` with a second argument:

      > for line in iter(f.readline, ''):

      > ... # process line

      See: https://docs.python.org/3/library/functions.html#iter

      • jl2718 5 years ago

        This is useful, but two totally different functions with the same name distinguished only by the presence, not even the value of an unused argument. Where else does anything like this exist in the language? Seems problematic.

        • dragonwriter 5 years ago

          > This is useful, but two totally different functions with the same name distinguished only by the presence, not even the value of an unused argument.

          The sentinel argument is not unused.

          > Where else does anything like this exist in the language?

          In the narrow sense of “in the language” (builtins only), it's unique. There may be other examples in stdlib. That aside, functions that do a descriptively similar thing (i.e.,“build an iterator”) but where the details of how they do it differ significantly by aritt aren't weird among programming languages generally; don't see why it would be particularly problematic.

    • kbd 5 years ago

      For sure. Walrus operator is "unnecessary" but is a clear improvement in the code that will use it.

  • thomasahle 5 years ago

    The problem with `while line := f.readline():` is that it takes preasure of library writers. You should really just do `for line in f:`. If the library only has a `next` function, it needs to be fixed.

    • masklinn 5 years ago

      `f` might be iterable / iterator with completely different semantics than doing by-line iteration. And that might even be a good idea.

      • thomasahle 5 years ago

        In this case it isn't though. And if it were, you could provide an `f.lines()` iterator. The code would be much nicer that way.

sleavey 5 years ago

Without wanting to ignite a debate about the walrus operator (and having not read any of the arguments), I can guess why there was one. It's not clear to me what it does just from reading it, which was always one of Python's beginner-friendlinesses.

  • coldtea 5 years ago

    >It's not clear to me what it does just from reading it

    How isn't it entirely obvious? := is the assignment operator in tons of languages, and there's no reason not to have assignment be an expression (as is also the case in many languages).

    • txcwpalpha 5 years ago

      > := is the assignment operator in tons of languages

      It is? Which ones? Other than Go, I can not think of a single language that has ":=" as an operator. Java does not, JavaScript does not, C/C++ do not, Ruby does not, I don't think PHP does, Erlang/Elixir do not, Rust does not... (I could be wrong on these, but I've personally never seen it in any of these languages and I can't find any mention of it in these languages' docs).

      I tried looking around the internet at various popular programming languages and the only ones I could find that use ":=" are: Pascal, Haskell (but it's used for something else than what Python uses it for), Perl (also used for something else), and Scala (but in Scala it isn't officially documented and doesn't have an 'official' use case).

      I don't have a strong opinion about ":=" in Python but I do agree that it's unintuitive and thus not very "Pythonic".

      • pavon 5 years ago

        It was the assignment operator in Algol, which along with Fortran and Lisp was one of the most influential programming languages for decades. Its basic syntax was the prototypical "psuedo-code" in textbooks for decades after that.

        The operator was inherited by Pascal, Ada, Delphi. That line of language syntax died off in the late 90's though, so I can see why younger (and in particular self-taught) programmers wouldn't be familiar with it.

      • hathawsh 5 years ago

        See: https://en.wikipedia.org/wiki/Assignment_(computer_science)#...

        At least 18 prominent languages use that syntax.

        • megla_ 5 years ago

          I genuinely haven't heard of 13 of those and I'd say I'm quite interested in learning about languages. The few that I know, were just briefly mentioned by a professor, so I don't know anything apart from the name.

          What qualifies as prominent to you? How old are you? On Tiobe Index only Pascal and Go are in the first 50, while half of them aren't even listed in the first 100. Sure they're important and had an impact on new languages, but most of them were made ~50 years ago.

          So many new languages were developed since then, which are far more useful and prominent than these legacy ones. If almost none of the modern ones have implemented it so far, is it really that useful/needed?

          • coldtea 5 years ago

            >I genuinely haven't heard of at least a third of them and I'd say I'm quite interested in trying new (and possibly unusual) languages.

            But perhaps not as interested in trying old and significant languages?

            >What qualifies as prominent to you? On Tiobe Index only Pascal and Go are in the first 50, while half of them aren't even listed in the first 100. Sure they're important and had an impact on new languages, but most of them were made ~50 years ago.

            Well, Lisp was made 60+ years ago, and C 50 years ago, so?

            Besides Go, Smalltalk, Ada, and Pascal would be significant languages in any book, and I'd add Simula, Oberon, Eiffel, and Dylan to the list.

            Seriously, if one haven't at least heard of Simula (the father language of OO) I'm not sure how qualified they are to pass PL judgement.

            • megla_ 5 years ago

              >Well, Lisp was made 60+ years ago, and C 50 years ago, so?

              Well, they're still seeing widespread use, that's why they're on Tiobe, while others faded into obscurity. Those languages are historically significant, but nowadays they're basically useless apart from scientific use and maintaning old software.

              Maybe you should understand that the majority of programmers are younger than Python and don't study the same material they did 30 years ago, because a whole lot of history happened in that time. Also I'm not sure how not knowing about Simula makes me unqualified for anything.

              I've noticed, not just in this reply, but in all of your comments; your condescending tone and indirect addressing make you seem like an unpleasant person.

              Using these qualities makes one seem like some stuck-up pseudointellectual boomer.

        • Redoubts 5 years ago

          > At least 18 prominent languages use that syntax.

          There aren't even 18 prominent languages...

        • txcwpalpha 5 years ago

          That's more than I was aware of, but I would hardly call 90% of those "prominent". Sorry to any fans of those languages, but I doubt even most people here on HN have even heard about over half of the languages in that ":=" list.

          • coldtea 5 years ago

            If someone is not, not a user, but familiar with ALGOL, Simula, Pascal, Modula, Ada, PL/M, Smalltalk, Eiffel, and Oberon, they should not really promote their programming language ideas as relevant...

            The fact that they use some "new languages" (e.g. whatever derivative stuff happens to be in fashion atm) and are not even aware of the debt of those languages to the list above, doesn't qualify them...

            • txcwpalpha 5 years ago

              Just because you're an old programming elitist that is familiar with completely out-of-use (and most not even maintained now) languages doesn't qualify you, either. I don't gatekeep book authors by their knowledge of the ancient Sumerian language, and anyone who tries to do so would rightfully be laughed out of the room.

            • Redoubts 5 years ago

              > If someone is not, not a user, but familiar with ALGOL, Simula, Pascal, Modula, Ada, PL/M, Smalltalk, Eiffel, and Oberon, they should not really promote their programming language ideas as relevant...

              If programming is intellectual onanism for you, then sure you're free to entertain that idea.

      • dwohnitmok 5 years ago

        It shows up fairly frequently in pseudocode, especially for BNF syntax rules. I also (probably as a result) have come across it often-ish in embedded DSLs if the host language already uses = for assignment.

        So from the perspective of Python as executable pseudocode it makes some sense.

      • kxrm 5 years ago

        Delphi uses this as an assignment operator but it certainly isn't a popular choice in most mainstream languages.

      • abraae 5 years ago

        Oracle's PL/SQL uses it. I believe it was based on ADA... googles ... Yes ADA uses it as well.

    • queensnake 5 years ago

      It looks to me like it could be an assignment to const, or, a copy vs a non-copy - it’s not obvious at all. I’m sure: ‘?=‘ was fought over and rejected, but that’s what I’d have expected conditional assignment to look like.

      • xaedes 5 years ago

        It is not "conditional assignment" tho. It is an assignment which returns the assigned value. You can use it in conditions, but you can also use it elsewhere.

    • sleavey 5 years ago

      It's not in a language I've ever used (furthermore, I explicitly mentioned beginners in my comment).

      • coldtea 5 years ago

        Well, beginners wont know generators, list comprehensions, asyncio, keyword arguments, and tons of other things either...

gclaugus 5 years ago

Walrus operator looks like a great addition, not too much syntax sugar for a common pattern. Why were folks arguing about it?

  • sametmax 5 years ago

    It's the most controversial feature ever introduced because it goes against a lot of python culture and philosophy.

    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.

    • mixmastamyk 5 years ago

      Lesson: Reverse 25 year-old design decisions at your own peril.

    • andrewshadura 5 years ago

      Oh come on, it doesn't.

      • sametmax 5 years ago

        My metric for this is to put some of my freshest student in front of a code and see how they deal with it. How easily can they understand it ? How easily can they write it ? Debug it ?

        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.

        • llukas 5 years ago

          > my freshest student in front of a code and see how they deal with it.

          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.

          • mbreese 5 years ago

            It's not about experience vs inexperience... it's about code readability and being unsurprising.

                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.
            • clinta 5 years ago

              Python already has " as " operator that I think is very readable.

                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 ...
            • owaislone 5 years ago

              If feel Go solves this in a much more readable way.

                  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.
              • mkl 5 years ago

                How is that more readable? It's identical except for ":" -> ";", and some extra symbols added. Needing to repeat "m" seems seems redundant, and particularly bad for readability as it moves the actual condition far away from the "if".

                • owaislone 5 years ago

                  It is better IMO because it doesn't merge two things into one. It simply translates to `if <assignment>; <condition> { <body> }` as a generic rule. Variable used in condition may or may not be the same one in assignment. Bundling assignment and condition is what people don't like about this feature.

          • sametmax 5 years ago

            It's not, it's correlation between fresh student, and what happens in the field.

        • nerdponx 5 years ago

          I for one predict that the new operator will appear very sparingly, in while loops and code golf competitions.

          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?

          • PeterisP 5 years ago

            I'd expect the new operator to become the idiomatic way to write certain quite common things, for example regexp group matching and objects returned by dictionary .get() - currently you always need a dummy variable to check if it's not None before you use it.

          • upofadown 5 years ago

            Excess complexity almost always comes in small increments...

            • nerdponx 5 years ago

              Fair. Fortunately with all the blowback over the walrus operator I don't think we will be seeing any new operators for a long time.

  • adjkant 5 years ago

    I write a good deal of python and I can't think of a line of code that I would use it for besides the while loop on a non-iterable data source, which is such a once in a blue moon case. As mentioned by others, the operator invites more ways to do the same thing, which is not what Python has been viewed as being about.

    • orangecat 5 years ago

      Victor Stinner made a demonstration pull request using the walrus operator in the standard library where it makes sense. On balance it removes several hundred lines and often makes the code much clearer, e.g. https://github.com/python/cpython/pull/8122/files#diff-78e8e...

      • mixmastamyk 5 years ago

        The argument was about mostly about the syntax.

        In the link above, the "as" keyword would work with (very close to) all of those lines and arguably more readable.

    • drexlspivey 5 years ago

      I do this all the time:

      x = function_that_might_return_none()

      if x: do_stuff

  • chrisseaton 5 years ago

    I don't know how you read it - 'if x is assigned the value y'? Most other things in Python can just be read out loud.

    • thaumasiotes 5 years ago

      Read it "if y" - that's what's being tested.

      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.

      • txcwpalpha 5 years ago

        >Read it "if y" - that's what's being tested.

        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.

        • thaumasiotes 5 years ago

          You will end up with the same code under two conditions:

          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.
          • txcwpalpha 5 years ago

            That second point is quite an assumption to make. If it's okay to end up with the second one of your examples (without the ":=" operator), why did we need to add the walrus opeprator at all?

            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.

            • thaumasiotes 5 years ago

              > If it's okay to end up with the second one of your examples (without the ":=" operator), why did we need to add the walrus operator at all?

              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"?

              • txcwpalpha 5 years ago

                >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.

                • thaumasiotes 5 years ago

                  > 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.

                  • txcwpalpha 5 years ago

                    >Every now and then?

                    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.

          • shakna 5 years ago

            There's absolutely no guarantee that two calls to y result in the same value.

            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.

    • JackC 5 years ago

      You could read "if x := y()" as "if x gets a truthy value from y()."

      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.

      • chrisseaton 5 years ago

        So := is 'gets a truthy value from'? That seems to work.

        > 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?

        • dragonwriter 5 years ago

          > So := is 'gets a truthy value from'?

          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>)”

        • nerdponx 5 years ago

          How about "assigns to and returns"?

        • baq 5 years ago

          we added new syntax for a code pattern that has inherent complexity which can't be reduced.

          • chrisseaton 5 years ago

            It can be reduced into two simpler lines can’t it, both of which could be understood in isolation.

            • baq 5 years ago

              understanding lines in isolation is precisely besides the point here, because the code pattern has to be understood as a whole.

              • chrisseaton 5 years ago

                I don’t see why. ‘Assign x’ and ‘is x truthy’ can be understood separately. Worry about what x is being assigned. Then worry about whether its value is truthy.

                • baq 5 years ago

                  like I said, the whole pattern is more than two lines. the pattern is actually assign-test-fallback-test-fallback-test-etc.

                  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)
    • ignaloidas 5 years ago

      Personally, I think they should have went with `if y as x:` syntax, as I think that makes it clearer what it does

    • dragonwriter 5 years ago

      > I don't know how you read it

      “... x := foo ...” is read “... x, which is foo, ...”

      • Dylan16807 5 years ago

        I'd go with "set to" but sure that sounds easy enough.

  • joshuamorton 5 years ago

    It's not that common. There's 1 place where its useful imo (comprehensions to avoid duplicate calls), but even that can be handled case by case, and it certainly isn't a common thing.

    • theli0nheart 5 years ago

      Disagree. In my experience (albeit, not very long, been writing Python since 2007 or so), assigning to a value and checking for truthiness is a very common pattern.

      • noname120 5 years ago

        Very common pattern, confusing nonetheless. It does two different things at once where traditionally Python is explicit and only does one thing at once.

        • nerdponx 5 years ago

          This is probably the one argument against it that I agree with: I don't actually like it when I see it in other languages!

    • coldtea 5 years ago

      It's extremely common.

      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...

  • hdfbdtbcdg 5 years ago

    Because it goes against 20 years of the principles behind the language.

    • coldtea 5 years ago

      Actually it doesn't violate any of the principles behind the language. It could have been there from day one, like tons of others things added later and now totally loved.

      I should know, I've worked with Python for 22 years...

      • sametmax 5 years ago

        Guido disagrees and rejected the idea multiple time in the last 2 decades. I think he worked on Python for a long time too :)

        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.

        • ben509 5 years ago

          Quoth the PEP[1], Guido changed his mind when he found proof that coders would write redundant (and expensive) code to avoid using a separate line to construct a temporary variable.

          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-...

          • sametmax 5 years ago

            20 years after. It took 2 decades. My impression from the debate, and taking in consideration the political context, is that he saw that as the tipping point of the BDFL transition and a good test run as much as a language feature.

            • ben509 5 years ago

              I'm not following what you're saying it's a test run of. I agree that he probably wanted to cease being BFDL because it's a big job, but with the caveat that I'm terrible at following Internet drama, he did seem genuinely surprised at the outrage.

              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.

        • coldtea 5 years ago

          >Guido disagrees and rejected the idea multiple time in the last 2 decades. I think he worked on Python for a long time too :)

          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.

        • orf 5 years ago

          That’s an impressively incorrect history of the operator.

          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.

        • shaklee3 5 years ago

          See other replies. Guido was for the operator.

          • sametmax 5 years ago

            See my other replies as well.

      • hdfbdtbcdg 5 years ago

        I worked with Python for many years as well. I recently switched to another language...

        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.

  • coldtea 5 years ago

    Change aversion.

traderjane 5 years ago
  • ehsankia 5 years ago

    I don't know why the downvotes, but I personally much prefer this to the editorialized and incomplete list in the current list.

    Looking at the module changes, I think my top pick is the changes to the `math` module:

    > Added new function math.dist() for computing Euclidean distance between two points.

    > Added new function, math.prod(), as analogous function to sum() that returns the product of a ‘start’ value (default: 1) times an iterable of numbers.

    > Added new function math.isqrt() for computing integer square roots.

    All 3 are super useful "batteries" to have included.

mottosso 5 years ago

Very much looking forward to assignment expressions! It's something I've wanted to do every so often, only to realise that you can't. A worthy addition to the already intuitive Python language.

  • tomd3v 5 years ago

    Seriously. I recently came from PHP, and this is one feature I've been missing quite often and a lot.

Alex3917 5 years ago

Have there been any performance benchmarks done on Python 3.8 yet? I'd be interested in seeing how it compares to 3.6 and 3.7, but haven't seen anything published.

  • gonational 5 years ago

    Absolutely this.

    I think that the most important thing Python can do in each release is to improve performance, incrementally.

president 5 years ago

Anyone else think the walrus operator is just plain ugly? There is a certain aesthetic quality that I've always appreciated about the Python language and the walrus operator looks like something straight out of Perl or Shell.

  • brown9-2 5 years ago

    Looks pretty normal if you do any amount of Go.

  • ptx 5 years ago

    It's also used in Algol, Pascal, Modula and other perfectly respectable languages.

gonational 5 years ago

I recommend a talk from Pycon 2019, wherein Dustin Ingram explains PEP-572 (aka the Walrus Operator) better than I’ve seen done elsewhere.

IMHO, the usefulness of this new operator outweighs the slight learning curve required to get past the awkwardness you will experience when you are first acquainted to it.

Here is that talk:

https://youtu.be/6uAvHOKofws

ohazi 5 years ago

Also type hints for dictionaries with fixed keys:

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

I know it's almost always better to use objects for this, but tons of code still uses dictionaries as pseudo-objects. This should make bug hunting a lot easier.

  • lxmcneill 5 years ago

    Huh, was totally unaware of this. For me this has good implications for ingesting CSVs/.xlsx to dicts. Clean-ups / type hinting is required at times for dirtier documents.

lordnacho 5 years ago

Gotta ask how many of these changes are actually reflective of changing environments.

I could see with c++ that between 2003 and 2014 a fair few underlying machine things were changing and that needed addressing in the language.

But Python is not quite as close to the machine, and I don't see how something like the walrus is helping much. If anything it seems like you'd scratch your head when you came across it. And for me at least one of the main attractions of python is you're hardly ever surprised by anything, things that are there do what you guessed, even if you hadn't heard of them. Function decorators for instance, you might never have seen one but when you did you knew what it was for.

Same with the debug strings. That seems to be a special case of printing a string, why not leave it at that? I'm guessing a lot of people don't ever read a comprehensive python guide, what are they going to do when they see that?

  • thaumasiotes 5 years ago

    > I'm guessing a lot of people don't ever read a comprehensive python guide, what are they going to do when they see that?

    My guess would be "run it and see what it does".

stuaxo 5 years ago

It seems like the PEP0505 for None aware operator is delayed indefinitely.

It would be great if there was more momentum on this again, as it would be helpful in all sorts of places.

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

Waterluvian 5 years ago

The lack of the "nursery" concept for asyncio really sucks. Originally I heard it was coming in 3.8. Right now asyncio has this horrible flaw where it's super easy to have errors within tasks pass silently. It's a pretty large foot gun.

  • sametmax 5 years ago

    You can code your own wrapper for this.

    Like https://github.com/Tygs/ayo

    It's not as good as having it in the stdlib, because people can still call ensure_future and not await it, but it's a huge improvement and completly compatible with any asyncio code.

    • Waterluvian 5 years ago

      Yup for sure. My complaint is part ergonomics of boilerplate, part this really burned me bad and no stdlib documentation warns you upfront about it. So many hours of headscratching.

preommr 5 years ago

":=" is a fairly common operator symbol that I've seen used in other programming languages (e.g. Golang) and in mathematics. But I've never seen it called the "walrus" operator. Its fitting and memorable though, I like it.

BuckRogers 5 years ago

The problem with modern Python is that it's trying to recreate C# or Java. Which leaves it with nothing, because it'll only end up an inferior version of the languages/platforms of which it's attempting to duplicate.

When I was into Python, I liked it because it was a tighter, more to the basics language. Not having 4 ways to format strings and so forth. I don't think Python can defeat Java by becoming Java. It'll lose there due to multiple disadvantages. The way Python "wins" (as much as it could at least), is focusing on "less is more". They abandoned that a while ago.

My vision of a language like Python would be only 1-way to do things, and in the event someone wants to add a 2nd way, a vote is taken. The syntax is changed, and the old bytecode interpreter handles old scripts, and scripts written with the latest interpreter's bytecode only allows the new syntax. For me that's the joy of Python.

I think a lot of people wanted Python's original vision, "one way to do things". If I want feature soup, I'll use what I program in daily. Which I do want feature soup by the way, I just have no need to replace it with another "feature soup" language like Python turned into because it's inferior on technical and for me, stylistic levels.

  • orangecat 5 years ago

    My vision of a language like Python would be only 1-way to do things, and in the event someone wants to add a 2nd way, a vote is taken.

    By that standard, the walrus operator is not only acceptable but essential. Right now there are at least 3 ways to process data from a non-iterator:

      # 1: loop condition obscures what you're actually testing
      while True:
          data = read_data()
          if not data:
              break
          process(data)
    
      # 2: 7 lines and a stray variable
      done = False
      while not done:
          data = read_data()
          if data:
              process(data)
          else:
              done = True
    
      # 3: duplicated read_data call
      data = read_data()
      while data:
          process(data)
          data = read_data()
    
    There's too many options here, and it's annoying for readers to have to parse the code and determine its actual purpose. Clearly we need to replace all of those with:

      while (data := read_data()):
          process(data)
    
    Yes, I'm being a bit snarky, but the point is that there is never just one way to do something. That's why the Zen of Python specifically says one "obvious" way, and the walrus operator creates an obvious way in several scenarios where none exist today.
    • BuckRogers 5 years ago

      I have no opinion on this new feature, so I can't really engage in that debate over it. I still see no reason for smaller languages like Python to not operate as a true direct democracy. There's clearly frustration over the leadership in the PSF, so much so that Guido capitulated under the stress.

  • ptx 5 years ago

    The Zen of Python says that there should preferably be one obvious way to do it, not always strictly only one way.

    Also, this motto should be interpreted in the appropriate historical context – as taking a position in relation to that of Perl, which was dominant when Python was gaining popularity and had the motto "there's more than one way to do it".

RcouF1uZ4gsC 5 years ago

I find the different philosophies of languages amazing.

Just recently 'Declined Proposal: A built-in Go error check function, “try”' https://news.ycombinator.com/item?id=20454966 made the front page, explaining how a controversial potential Go feature was being declined early.

Python on the other hand, went ahead with what seems to be a proposal at least as controversial as 'try' in Go.

philsnow 5 years ago

I noticed some changes to pickle; do people still use pickle for Real Work?

Potential vulnerabilities aside, I got bitten by some migration issue back in the 2.2 to 2.4 transition where some built-in types changed how they did their __setstate__ and __getstate__ (iirc) and that caused objects picked under 2.4 to not unpickle correctly under 2.2 or something like that. After that I never wanted to use pickle in production again.

  • brilee 5 years ago

    Pickle is only guaranteed to work within python versions and shouldn't be used as a long-term data storage strategy. It's really intended for quick-n-dirty serialization, or for multiprocessing communication, where the objects are ephemeral.

rcfox 5 years ago

I feel like I've been seeing a lot of these almost identical articles pop up all over. Walrus operator, f-string equals, positional-only arguments, yawn. None of that is really going to change your life.

There's a bunch of changes in the official "what's new" doc that I think are more interesting:

https://docs.python.org/3.8/whatsnew/3.8.html

* Run-time audit hooks, to see if your modules are making network requests, etc.

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

https://tirkarthi.github.io/programming/2019/05/23/pep-578-o...

* multiprocessing SharedMemory for fast data sharing between processes

https://docs.python.org/3.8/library/multiprocessing.shared_m...

* Duck-typing for the static annotation checkers

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

* Literal checking for the static annotation checkers. ie: It's not enough to check that you're passing a string for the mode in open(), you want to check that it's 'r' or 'w', etc.

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

* The compiler now produces a SyntaxWarning when identity checks (is and is not) are used with certain types of literals (e.g. strings, ints). These can often work by accident in CPython, but are not guaranteed by the language spec. The warning advises users to use equality tests (== and !=) instead.

* A bunch of speed and memory optimizations:

- "Sped-up field lookups in collections.namedtuple(). They are now more than two times faster, making them the fastest form of instance variable lookup in Python."

- "The list constructor does not overallocate the internal item buffer if the input iterable has a known length (the input implements __len__). This makes the created list 12% smaller on average."

- "Doubled the speed of class variable writes."

- "Reduced an overhead of converting arguments passed to many builtin functions and methods. This sped up calling some simple builtin functions and methods up to 20–50%."

tasty_freeze 5 years ago

I'm all in favor of the walrus operator for the for loop, but the first example given to justify it is code I'd never write. The first if does a return, so there is no need for the else: and indentation. I'm sure there are other code examples that would justify it, but this one is unconvincing.

  • duckerude 5 years ago

    The return statements make it a poor example. There's an example from the standard library in the PEP that has a similar shape:

      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)
  • wodenokoto 5 years ago

    Nice way in without walrus

        m = re.match(p1, line)
        if m:
            return m.group(1)
        m = re.match(p2, line)
        if m:
            return m.group(2)
        m = re.match(p3, line)
        ...
    
    With walrus:

        if m := re.match(p1, line):
            return m.group(1)
        elif m := re.match(p2, line):
            return m.group(2)
        elif m := re.match(p3, line):
    
    The example would have been better if it didn't have the return, but just a value assign or a function call.
Animats 5 years ago

The title made me think "Be afraid. Be very afraid". But it's all little stuff.

Unchecked type annotations remain the worst addition since 3.0. Actual typing might be useful; it allows optimizations and checking. But something that's mostly a comment isn't that helpful.

  • snicker7 5 years ago

    Both static checking and compilation can be implemented using third party libraries. I think projects like mypyc could be a real game-changer.

  • joshuamorton 5 years ago

    If you don't like unchecked annotations, then check them. It's not hard to do.

Grue3 5 years ago

>Python 3.8 programmers will be able to do: print(f'{foo=} {bar=}')

Ugh, how did this get approved? It's such a bizarre use case, and debugging by print should be discouraged anyway. Why not something like debug_print(foo, bar) instead (because foo and bar are real variables, not strings)?

  • jimktrains2 5 years ago

    I don't understand why you think print or log debugging is inherently bad.

    Also, it's part of the format string and not a special print function so that it can be used for logs and other output as well, not just the console.

    • Grue3 5 years ago

      >I don't understand why you think print or log debugging is inherently bad.

      I use it myself all the time, but it just shows the weakness of the tooling that people have to resort to such measures. Fortunately, some people are working on it [1].

      >Also, it's part of the format string and not a special print function so that it can be used for logs and other output as well, not just the console.

      Since print (and hypothetical debug_print) are no longer statements like in 2.x, there's nothing preventing them from returning the string that's supposed to be printed. For example print's keyword file is sys.stdout by default. Why not borrow from Common Lisp's format and make it return the string if file=None is passed? Then you could do logging.warning(debug_print('Unusual situation', foo, bar, file=None)) and it would print "WARNING: Unusual situation: foo=foo_value, bar=bar_value" to the logs. It's so much clearer.

      [1] https://github.com/cool-RR/pysnooper

      • jimktrains2 5 years ago

        > I use it myself all the time, but it just shows the weakness of the tooling that people have to resort to such measures.

        It's not resorting to anything. It's a valid means of debugging. People use it even in languages like c and Java and in-browser JavaScript with very capable debuggers. It's quick, simple, and doesn't require intervention to record or examine anything.

        > Why not borrow from Common Lisp's format and make it return the string if file=None is passed?

        Because thatsa terrible idea because it's non-intuitive, verbose, and potentially confusing. Debug format strings are common in other languages, such as rust, so this isn't some half-thoughtout, python-only idea.

      • kazinator 5 years ago

        That's poor compared to just logging.warning('Unusual situation', foo, bar).

        I.e. since print isn't a statement, you can give other functions the same argument conventions that it has, instead of making the programmer use a string-generating shim.

        Speaking of Common Lisp, it has functions other than format which take format arguments.

          $ clisp -q
          [1]> (error "value of ~s should be less than ~s" 'bloop 42)
        
          *** - value of BLOOP should be less than 42
          The following restarts are available:
        • Grue3 5 years ago

          I don't expect logging.warning to change in future versions of Python (currently it substitutes extra args as % operator, so you'd have to write logging.warning('Unusual situation foo=%s, bar=%s', foo, bar)) since it would unnecessarily break too much code. But since print doesn't return any usable value, it can be easily updated to return a useful value.

antpls 5 years ago

At first, after reading the comments and before reading the article, I thought everyone was just casually bashing because of change. But just look at this :

def fun(a, b, /, c, d, *, e, f):

or

print(f'{now=} {now=!s}')

and guess what it does before actually reading the article.

Worst, the rationales of the PEPs are weak, presenting improvement for "performances" or enforcement of API because of low level stuff as C.

Back when I was 18 years old, Python was high level, rules were simple with only one way of doing things and performances weren't a concern, because you would just use the right language for the right task. There was no enforcement and you could always hack a library to your liking. Python now is getting closer to what Perl looked to me 10 years ago, trying to optimize stuff it shouldn't

atiredturte 5 years ago

I feel like walrus operators, while a cool construct, are at odds with "The Zen of Python".

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

If this was any other language, the addition would be welcome, but I feel that the walrus operator fundamentally disagrees with what python is about.

It's not about terseness and cleverness, it's about being clear, and having one way to do things (Unless you are Dutch).

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

Myrmornis 5 years ago

I believe that I hit places where I'd use the walrus about once every few hundred lines of python, so I do see a use for it. OTOH I am worried that it makes the language harder to understand for beginners, and that is a very important role Python plays in the world of programming languages.

The abbreviated f-string syntax looks weird and kinda wrong to me. But then I'm not even sure I've got comfortable yet with the object field initialization shortcuts in Javascript and Rust (where you also get to omit stuff to avoid repeating yourself).

wil421 5 years ago

>Debug support for f-strings.

F strings are pretty awesome. I’m coming from JavaScript and partially java background. JavaScript’s string concatenation can become too complex and I have difficulty with large strings.

>Python 3.8 programmers will be able to do: print(f'{foo=} {bar=}')

Pretty cool way to help with debugging. There are so many times, including today, I need to print or log some debug string.

“Debug var1 ” + var1 + “ debug var2” + var2...and so on. Forgot a space again.

  • joaolvcm 5 years ago

    By the way, this has nothing do with f strings but for debugging JavaScript you can do something like

    console.log({var1,var2,var3});

    And the logged object will get created with the variables content and the variable nem as key, so it will get logged neatly like

    {var1: "this is var1", var2: 2, var3: "3"}

punnerud 5 years ago

Is there anything similar to BabelJS for Python? Now after 3.8 I start to feel there are a need for a tool like that.

More compact code at the cost of higher learning curve.

nickthemagicman 5 years ago

Its kind of amazing to me switching from PHP/Ruby to Python, that things like f strings and walrus operators are just now being added to python.

jasonrhaas 5 years ago

The walrus operator does not feel like Python to me. I'm not a big fan of these types of one liner statements where one line is doing more than one thing.

It violates the philosophies of Python and UNIX where one function, or one line, should preferably only do one thing, and do it well.

I get the idea behind the :=, but I do think it's an unnecessary addition to Python.

  • andrewf 5 years ago

    This has never felt like a Pythonic principle to me. Python has always seemed like a high-level language that enables dense code. Look at the docs for list comprehensions! https://docs.python.org/2/tutorial/datastructures.html#list-...

    A lot of folks see Go as a Python successor which surprises me because I don't think the languages favor the same things at all. Maybe my perspective is weird.

  • jstimpfle 5 years ago

    I support your view, but want to make you aware that early unix did favour a little cleverness to reduce line counts (and even character counts). C's normal assignment operator does what python's walrus does, for example. Or look at pre/post increment/decrement operators. Or look at languages like sed, or bc, they try to be terse over anything else.

  • fatbird 5 years ago

    The unix philosophy of simplicity was on a per tool basis, not function or line of code. The walrus operator is Python version of what we can do now in C or in JS, doing plain assignment in an expression while evaluating it for truthiness. And more often than not, the point of that single-purposeness in Unix is so you can chain a bunch of piped commands that result in a perl-like spaghetti command that's three terminal widths long.

    • jstimpfle 5 years ago

      > while evaluating it for truthiness

      no, it evaluates to the left side's value after assignment

      • fatbird 5 years ago

        Well, yes, that's right: the return value of an assignment expression is the left side's value, which is what makes the assignment/evaluation work.

  • coldtea 5 years ago

    >It violates the philosophies of Python and UNIX where one function, or one line, should preferably only do one thing, and do it well.

    Python never had that philosophy... You might confused it with "there should be one, and preferably only one, obvious way to do anything".

ProjectBarks 5 years ago

The changes to f-strings just seems like a step in the wrong direction. Don't make the string content implicit!

  • strictfp 5 years ago

    Also, why abandon printf-style? All languages tend to converge to printf over time, it's simply the most tried and tested model out there!

    • bvrmn 5 years ago

      Format string is very inconvenient approach because you need to duplicate type information.

      >>> '%i' % 's' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: %i format: a number is required, not str >>> '{}'.format('s') 's' >>> '{}'.format(10) '10'

    • joshuamorton 5 years ago

      javascript, python, rust, etc. don't use printf style, but instead use the {} style.

      • strictfp 5 years ago

        Yeah, well Rust isn't exactly a success story in that regard if you ask me. A couple of weeks ago I tried to figure out how to format a float properly in Rust, and the way they made it work is a lot worse than straight up printf-style if you ask me.

mcdermott 5 years ago

Python has "jumped the shark" for me. Python is no longer Pythonic (the "import this", zen of python easter egg should be removed). It's lost it way and is TIMTOWTDI now, heading for that Perl 6 brass ring. Golang is now the Pythonic language.

tasubotadas 5 years ago

I'll just put a reminder here that it's the year 2019 and AMD and Intel has 10-core CPUs while Python is still stuck with GIL ¯\_(ツ)_/¯

jpetrucc 5 years ago

I love the f-strings and the new enhancements, but I'm still skeptical about the walrus operator and the positional argument change.

outerspace 5 years ago

Does it make sense to use := everywhere (can it be used everywhere?) instead of just in conditionals? Just like Pascal.

  • DonHopkins 5 years ago

    About as much sense as it makes to use ; after every Python statement. Just like Pascal.

    (Yeah I know, ; is a statement separator, not a statement terminator in Pascal.)

    As long as you're being just like Pascal, did you know Python supported Pascal-like "BEGIN" and "END" statements? You just have to prefix them with the "#" character (and indent the code inside them correctly, of course). ;)

        if x < 10: # BEGIN
            print "foo"
        # END
  • ben509 5 years ago

    It's not valid in an assignment statement, so you can't use it everywhere.

    FWIW, I agree with the sentiment; I use := for assignment in my language precisely because that's the correct symbol. But even there, my grammar accepts = as assignment as well because I type it from habit.

singularity2001 5 years ago

Do parsers of previous pythons emit warnings: "this feature is not available in pythons 3.3 3.4 3.5 etc" ?

  • ben509 5 years ago

    No, just a SyntaxError.

    Generally, library authors won't be able to use it if they want to support many versions; same as with f-strings.

vkaku 5 years ago

That walrus operator has given me exactly what I wanted from C. Although I'd have preferred:

if val = expr():

  • hyperion2010 5 years ago

    That particular version opens the way for massive typo footguns and results in the insanity of defensive programming patterns like yoda expressions.

    • vkaku 5 years ago

      Well, for those used to those expressions, it definitely helps write that code with one line lesser (assignment by itself).

      Most likely, the assigned value is stored for use in one of the conditionals, so it really doesn't change any of that.

      Let's also understand that we are dealing with a decorated assignment here, so a = (b = c) should be no different from evaluating (b = c). It's not complicated, the way I at least look at it.

      • vkaku 5 years ago

        But now I see your point. A language must not give beginners an option to shoot themselves in the foot.

ihuman 5 years ago

How come they are using a new := operator instead of using equals?

  • andolanra 5 years ago

    They address this briefly in the PEP[0], and it's largely because they want to be very clear about when it's happening. The distance between

        if x = y:
    
    and

        if x == y:
    
    is very small, and easy to ignore, so insisting on

        if x := y:
    
    makes it very clear that what's happening won't be mistaken for comparison at a quick glance.

    [0]: https://www.python.org/dev/peps/pep-0572/#why-not-just-turn-...

  • jimktrains2 5 years ago

    That's literally the point: it's not the assignment operator.

    The difference between = and == in an if causes many hugs in other languages. Using := for assignment in an expression instead of == means that you can't simply have a typo and have a bug.

  • dragonwriter 5 years ago

    Which equals?

    = (existing) is statement assignment

    == (existing) is expression equality

    := (new) is expression assignment

    • ihuman 5 years ago

      Just 1 equals. It could assign a statement to a variable, and return that value/variable to the if statement to check for truthyness

         a=42
         if b = a:
           print(b)
         else:
           print("no")
      
      Would print "42". It works in C

        int a,b;
        a=42;
        if(b=a){
          printf("%d\n",b);
        } else {
          printf("no\n");
        }
      • magicalhippo 5 years ago

        It works in C, and have caused countless bugs in C (and C++).

        So much so that many have adopted the rule that the variable goes on the right, "if 42 = b", to make sure the compiler barfs when you intended to write "if b == 42".

        With := it's less likely that mistake is made. I also find it visually more distinct, so easier to parse, but that might be very subjective.

      • dragonwriter 5 years ago

        That works if “if” statements were the only place the assignment expression operator could be used.

        It works less well if they can be used everywhere an expression can occur, including the right side of assignments—especially since Python has both multiple (x = y, z) and chained (x = y = z) assignment, which can be used together.

        What does this mean if = is used for both assignment statements and assignment expressions:

          x = y, z = 10, 20
        
        When they are distinct, these have different meaning:

          x = y, z = 10, 20  # x: (10, 20), y: 10, z: 20
          x = y, z := 10, 20 # x: (<existing value of y>, (10, 20)), y: <unchanged>, z: (10, 20)
dirkg 5 years ago

What Python needs is a better lambda syntax similar to JS and true anonymous multiline functions. Defining and using lambdas in Python feels very unpythonic, this is something JS gets perfectly.

Also fix the GIL.

RocketSyntax 5 years ago

Isn't the walrus just like a case statement?

musicale 5 years ago

All I care about is allowing a print statement in addition to the print function. There's no technical reason why both can't coexist in a perfectly usable manner.

  • mixmastamyk 5 years ago

    Try an editor snippet like I did years ago. It's even shorter to type:

        pr<TAB>  -->  print(" ")
                      #      ^ cursor
dec0dedab0de 5 years ago

I dont like the positional only arguments..

Really, I dont like anything that trys to force a future developer into using your code the way you expect them to.

  • nneonneo 5 years ago

    One of the use-cases for positional-only arguments strikes me as being very sensible:

        def my_format(fmt, *args, **kwargs):
            ...
            fmt.format(*args, **kwargs)
    
    suffers from a bug if you want to pass fmt as a keyword argument (e.g. `my_format('{fmt}', fmt='int')`). With positional-only arguments that goes away.

    You could always force developers into using your code the way you expect by parsing args/kwargs yourself, so it's not like this really changes anything about the "restrictiveness" of the language.

  • duckerude 5 years ago

    I think the main value is that function documentation becomes slightly less absurd.

    If you run `help(pow)` as early as Python 3.5 it lists the signature as `pow(x, y, z=None, /)`. The first time I saw that `/` I was pretty confused, and it didn't help that trying to define a function that way gave a syntax error. It was this weird thing that only C functions could have. It's still not obvious what it does, but at least the signature parses, which is a small win.

    Another thing it's good for is certain nasty patterns with keyword arguments.

    Take `dict.update`. You can give it a mapping as its first argument, or you can give it keyword arguments to update string keys, or you can do both.

    If you wanted to reimplement it, you might naively write:

      def update(self, mapping=None, **kwargs):
          ...
    
    But this is wrong. If you run `d.update(mapping=3)` you won't update the 'mapping' key, you'll try to use `3` as the mapping.

    If you want to write it in pure Python < 3.8, you have to do something like this:

      def update(*args, **kwargs):
          if len(args) > 2:
              raise TypeError
          self = args[0]
          mapping = None
          if len(args) == 2:
              mapping = args[1]
          ...
    
    That's awful.

    Arguably you shouldn't be using keyword arguments like this in the first place. But they're already used like this in the core language, so it's too late for that. Might as well let people write this:

      def update(self, mapping=None, **kwargs, /):
          ...
stesch 5 years ago

No new way to format a string?

Areading314 5 years ago

Very much seems like perlification, and we all know what happened to Perl.

Although that being said I always really liked Perl

  • lizmat 5 years ago

    Perhaps it's more Perl 6-ification?

ggm 5 years ago

And the GIL...

terminalhealth 5 years ago

tl;dr: Computation is being compressed ever more

patientplatypus 5 years ago

Personally, I vote against the walrus. Code complication for a limited set of use cases. Boo, bad walrus.

xaedes 5 years ago

Wow. Never would I have guessed the amazing concept of assignment expression is so confusing for, what it seems, a lot of python programmers. It really was time to introduce it to them.

  • jpetrucc 5 years ago

    It's not really that it's confusing, more so that it isn't necessarily 'pythonic'

GrumpyNl 5 years ago

Why elif en not juste elseif?

  • akubera 5 years ago

    Perhaps to align with the final "else" clause, or it was familiar to c programmers due to the c-preprocessor directive https://gcc.gnu.org/onlinedocs/cpp/Elif.html, or they were mindful that every character counts when you want to push 80 character max-line-length style?

    To be clear, that's not a new feature in 3.8.

  • dreary_dugong 5 years ago

    It fits in a single indent space. At least that's what my professor told us, and it seems to be confirmed by a quick online search.

  • mehrdadn 5 years ago

    Or just else if... but honestly elif is easiest to type and it's not hard to understand.

    • reallydude 5 years ago

      Hard is being used in a "type the keys" sense. It's more complexity to borrow idioms from languages then slightly change the syntax (PHP!), which isn't necessary. Like most languages, choices are made without evidence (but plenty of anecdotes and personal style).