Re: [Python-Dev] Examples for PEP 572
On Wed, 4 Jul 2018 at 07:42 Antoine Pitrou wrote: > On Wed, 4 Jul 2018 09:43:04 -0300 > Brett Cannon wrote: > > > > I think this is a very key point that the "this is bad" crowd is > > overlooking. Even if this syntax turns out to not be that useful, abusing > > the walrus operator can be fixed with a comment of "hard to follow; > please > > simplify" without teaching any new concepts or idioms > > The same could be said of any language mis-feature. Do we want to > claim that questionable semantics in Javascript and PHP are not a > problem, because the bad constructs can simply be turned away in code > review? > > That sounds like a modern re-phrasing of the old argument, """C is not > dangerous in itself, it's only the fault of incompetent programmers""". > Just replace "incompetent programmers" with "complacent reviewers"... > I would disagree as for some things understanding why it needs a change is much easier than others. For instance saying that some use of := is too convoluted and should be simplified needs much less explanation than other things like why you should typically avoid staticmethod. Or another way to view it, saying := is abused in a review should be universally understood while something else may require a more Python-specific explanation and deeper knowledge. Now none of this isn't to say we should take any idea regardless of potential abuses and maintenance cost. But for me, I don't view this as requiring any innate knowledge to cause people not to abuse it. > > > Another point is we live in a dictatorship by choice, and yet some people > > seem very upset our dictator dictated in the end. > > Not sure what you mean with "by choice". As in people choose to join this team knowing that Guido is the BDFL and what that entails. Since none of us have to be here I view it as a choice to be here. -Brett > When I arrived here, I > certainly wasn't asked whether I wanted the place to be a dictatorship > or not ;-) Granted, I did choose to come here, but not because of a > personal appeal for dictatorship. > > One could claim that the qualities of Python are due to it being a > dictatorship. I think it's impossible to answer that question > rigorously, and all we're left with is our personal feelings and biases > on the subject. > > Regards > > Antoine. > > > ___ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/brett%40python.org > ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 2018-07-04 00:25, Nathaniel Smith wrote: The only cases that seem potentially valuable to me are the ones that are literally the form 'if := ` and 'while := '. (I suspect these are the only cases that I would allow in code that I maintain.) The PEP does briefly discuss the alternative proposal of restricting to just these two cases, but rejects it because it would rule out code like 'if ( := ) '. But those are exactly the cases that I want to rule out, so that seems like a plus to me :-). The 'if as ' syntax would be a simple way to encode exactly these simple non-harmful cases. The PEP rejects it on the grounds that 'as' is already used in a different way by 'except' and 'with'. But... 'as' is *also* used in the *same* way by 'import', so the argument feels disingenuous. Yeah, there'd be an inconsistency, but that inconsistency already exists, and adding 'if ... as' and 'while ... as' wouldn't create any *new* inconsistencies. Agreed, tried to make this point in several threads. -Mike ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 7:42 PM Steven D'Aprano wrote: > On Wed, Jul 04, 2018 at 01:00:41PM -0700, Devin Jeanpierre wrote: > > On Wed, Jul 4, 2018 at 11:04 AM Steven D'Aprano wrote: > > > Did you actually mean arbitrary simple statements? > > > > > > if import math; mylist.sort(); print("WTF am I reading?"); True: > > > pass > > > > Yes. > > Okay, you just broke my brain. > > I was *sure* that you were going to complain that I was misrepresenting > your position, or attacking a strawman, or something. This "brain-breaking" experience is something to keep in mind when we read the reactions to the acceptance assignment expressions, so that we can better empathize with the people who are so shocked by it. After all, assignment expressions allow nearly word for word the same abuse you posted: if [(math := __import__('math')), mylist.sort(), print('WTF?'), True][-1]: ... Anything that allows assignment in an if statement is going to allow some messed up stuff. The PEP seems to intentionally take the stance that it is OK to allow super-ugly code, because we can trust people to just not do that. > I did not imagine for a second that you *actually* would prefer > to allow the above code over assignment expressions. I don't really know how to bridge that disconnect. I thought Nathaniel argued very well what is lost with assignment expressions. -- Devin ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 7:20 AM, David Mertz wrote: > > That said, this is a silly game either way. And even though you CAN > (sometimes) bind in an expression pre-572, that's one of those perverse > corners that one shouldn't actually use. > not only shouldn't by hardly anyone ever does / would. A lot of the argument for this feature is that it doesn't really let you do things you couldn't do before (like manipulate the local namespace in side comprehensions, or the nonocal one, or...) But this IS a silly game -- Python is highly dynamic, you can do all sorts of metaprogamming tricks. I'm pretty sure you can even alter the byte code in a running interpreter (but only pretty sure, 'cause why would I ever try to do that?) But the point is not that you can do tricky namespace manipulations now, it's that you need to do advanced (and obvious) thinks like call locals() or globals() or use nonlocal, or... I don't think these concerns have been ignored, but I also don't think that I've heard anyone on the pro side say something along the line of: "Yes, this does add a significant complication to the language, but we think it will be unlikely to be mis-used in confusing ways, and that complication is worth it." Rather, I've heard a lot of "but you can already do that" or "but we added [ternary expressions, augmented assignment, f-strings, ...]" And none of those add *complication* to the language itself -- they add one more feature that needs to be looked up when you encounter it -- but only effect the line of code where there are used. -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R(206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception chris.bar...@noaa.gov ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 7/4/2018 3:34 PM, Steven D'Aprano wrote: On Wed, Jul 04, 2018 at 03:24:08PM -0400, Terry Reedy wrote: On 7/4/2018 9:35 AM, Steven D'Aprano wrote: On Wed, Jul 04, 2018 at 05:02:07PM +1000, Chris Angelico wrote: On Wed, Jul 4, 2018 at 4:07 PM, Serhiy Storchaka wrote: "Assignment is a statement" -- that's exactly the point under discussion. I believe that this is Chris quoting and commenting on Serhiy having said 'assigment is a statement' Not any more it isn't. We've now gone from discussion to bitter recriminations *wink* I don't see any recrimination in what either said. Haven't you been reading the rest of the thread? About half of it. But I was responding here only to a few. The Twitter storm? No, not until I followed a link in something posted after I wrote the above. I have seen maybe 100 tweets in my life. The ranting on Reddit that this is the end of the world and Python is doomed? No. I wasn't referring specifically to Chris or Serhiy's comments, but about the general over-reaction, here and elsewhere. The few tweets I read gave me an idea of what you meant. -- Terry Jan Reedy ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 7/4/2018 2:32 PM, Sven R. Kunze wrote: Sorry for adding yet another mail. :-( On 04.07.2018 10:54, Serhiy Storchaka wrote: Sorry, this PEP was rewritten so many times that I missed your Appendix. while total != (total := total + term): term *= mx2 / (i*(i+1)) i += 2 return total This very example here caught my eye. Isn't total not always equal to total Repeat response given elsewhere. No. Python has limited precision floats, not reals. Floats do not obey laws of real numbers. >>> 1e50 + 1e34 == 1e50 True >>> 1e50 + 1e35 == 1e50 False Basic numerical analysis operation: approximate infinite sum of decreasing terms by summing terms until they become small enough that they can be ignored. -- Terry Jan Reedy ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 7/4/2018 1:50 PM, Yury Selivanov wrote: On Wed, Jul 4, 2018 at 1:35 PM Ivan Pozdeev via Python-Dev wrote: On 04.07.2018 11:54, Serhiy Storchaka wrote: while total != (total := total + term): term *= mx2 / (i*(i+1)) i += 2 return total This code looks clever that the original while loop with a break in a middle. I like clever code. But it needs more mental efforts for understanding it. I admit that this is a good example. There is a tiny problem with it (and with rewriting a while loop as a for loop, as I like). Often the body contains not a single break. In this case the large part of cleverness is disappeared. :-( It took me a few minutes to figure out that this construct actually checks term == 0. No. Floats are not reals. The test is that term is small enough *relative to the current total* that we should stop adding more terms. >>> 1e50 + 1e30 == 1e50 True 1e30 in not 0 ;-) Wow, I gave up on this example before figuring this out (and I also stared at it for a good couple of minutes). Now it makes sense. It's funny that this super convoluted snippet is shown as a good example for PEP 572. Although almost all PEP 572 examples are questionable. -- Terry Jan Reedy ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 01:00:41PM -0700, Devin Jeanpierre wrote: > On Wed, Jul 4, 2018 at 11:04 AM Steven D'Aprano wrote: > > Did you actually mean arbitrary simple statements? > > > > if import math; mylist.sort(); print("WTF am I reading?"); True: > > pass > > Yes. Okay, you just broke my brain. I was *sure* that you were going to complain that I was misrepresenting your position, or attacking a strawman, or something. I did not imagine for a second that you *actually* would prefer to allow the above code over assignment expressions. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 04.07.2018 4:26, Tim Peters wrote: [INADA Naoki] > ... > On the other hand, I understand PEP 572 allows clever code > simplifies tedious code. It may increase readability of non-dirty code. The latter is the entire intent ,of course. We can't force people to write readable code, but I don't understand the widespread assumption that other programmers are our enemies who have to be preemptively disarmed ;-) Use code review to enforce readable code. If you want a coding standard here, use mine: "if using an assignment expression isn't obviously better (at least a little so), DON'T USE IT". That's the same standard I use for lots of things (e.g., is such-&-such better as a listcomp or as nested loops?). It only requires that you have excellent taste in what "better" means ;-) As I noted in the PEP's Appendix A, I refuse to even write code like i = j = count = nerrors = 0 because it squashes conceptually distinct things into a single statement . I'll always write that as i = j = 0 count = 0 nerrors = 0 instead - or even in 4 lines if `i` and `j` aren't conceptually related. That's how annoyingly pedantic I can be ;-) Yet after staring at lots of code, starting from a neutral position (why have an opinion about anything before examination?), I became a True Believer. I really don't know what Guido likes best about this, but for me it's the large number of objectively small wins in `if` and `while` contexts. They add up. That conclusion surprised me. That there are occasionally bigger wins to be had is pure gravy. But in no case did I count "allows greater cleverness" as a win. The Appendix contains a few examples of "bad" uses too, where cleverness in pursuit of brevity harms clarity. In fact, to this day, I believe those examples derived from abusing assignment expressions in real-life code are more horrifying than any of the examples anyone else _contrived_ to "prove" how bad the feature is. I apparently have more faith that people will use the feature as intended. Not all people, just most. The ones who don't can be beaten into compliance, same as with any other abused feature ;-) It's not about if a syntax can be used right or wrong. It's about how easy it is to use it right vs wrong. A syntax, any syntax, naturally nudges the user to use it in specific ways, by making these ways easy to write and read. One of Python's hightlights is that it strives to make the easiest solutions the right ones -- "make right things easy, make wrong things hard". How many of the users are "professional" vs "amateur" programmers is irrelevant. (E.g. while newbies are ignorant, pros are instead constantly pressed for time.) Python Zen rather focuses on making it easy to write correct code for everyone, beginners and pros alike. (As Stéfane Fermigier righly showed in message from 4 Jul 2018 11:59:47 +0200, there are always orders of magnitude more "amateurs" than "professionals", and even fewer competent ones.) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/vano%40mail.mipt.ru -- Regards, Ivan ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 04.07.2018 21:18, Steven D'Aprano wrote: Read the Appendix to the PEP: https://github.com/python/peps/blob/master/pep-0572.rst Yes, I did after I realized where that example came from. But my point was actually to understand the evaluation order because Uncle Timmy won't be around to explain when new code appears. And no, total is not always not equal to total. Err, yeah. Double negation rules. ;-) I read it as: while total != updated total: do stuff and find it easier to follow than having to juggle the extra book-keeping "old" variable in the original code. updated_total rocks. Reminds me of those pattern, we usually use in those cases. What just confused me is the evaluation order. It seems to me that it's like left-to-right first and then assignment expression. Using some math-style-inspired markers (execution-irrelevant) would be cool: while total != (total' := total + term): do stuff total and total' can be different at the same whereas total is total (at least in my mental model). But it seems I need to adapt here. Regards, Sven ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 11:04 AM Steven D'Aprano wrote: > Did you actually mean arbitrary simple statements? > > if import math; mylist.sort(); print("WTF am I reading?"); True: > pass Yes. To quote PEP 572: "This is a tool, and it is up to the programmer to use it where it makes sense, and not use it where superior constructs can be used." > A more reasonable suggestion would be to only allow *assignments*, not > arbitrary simple statements. But that's another special case: I don't agree that it is more reasonable, for exactly the reasons you describe it to be surprising. > with one or more semicolon-separated statements between the "if" and the > condition: > > if statement; statement; condition: > > If we stick to the rule that semicolons separate statements, that means > we have: > > > if statement # SyntaxError > statement # okay > condition:# SyntaxError > > > If we don't want that, we need a new rule to treat semicolons > differently inside if statements that they're treated elsewhere. Yes. This is analogous to complaining that [1, 2, 3] should be a syntax error because clearly this is a tuple with three elements: "[1", "2", and "3]". In as far as it's a new parsing rule, it is a "special case" indeed. > If we applied this rule "allow statements separated by semicolons" > everywhere, we'd get this: [snip] Nobody said anything about allowing semicolon-delimited statements in arbitrary places in the grammar. -- Devin ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 03:24:08PM -0400, Terry Reedy wrote: > On 7/4/2018 9:35 AM, Steven D'Aprano wrote: > >On Wed, Jul 04, 2018 at 05:02:07PM +1000, Chris Angelico wrote: > >>On Wed, Jul 4, 2018 at 4:07 PM, Serhiy Storchaka > >>wrote: > > > >>"Assignment is a statement" -- that's exactly the point under discussion. > > I believe that this is Chris quoting and commenting on Serhiy having > said 'assigment is a statement' > > >Not any more it isn't. We've now gone from discussion to bitter > >recriminations *wink* > > I don't see any recrimination in what either said. Haven't you been reading the rest of the thread? The Twitter storm? The ranting on Reddit that this is the end of the world and Python is doomed? I wasn't referring specifically to Chris or Serhiy's comments, but about the general over-reaction, here and elsewhere. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 7/4/2018 9:35 AM, Steven D'Aprano wrote: On Wed, Jul 04, 2018 at 05:02:07PM +1000, Chris Angelico wrote: On Wed, Jul 4, 2018 at 4:07 PM, Serhiy Storchaka wrote: "Assignment is a statement" -- that's exactly the point under discussion. I believe that this is Chris quoting and commenting on Serhiy having said 'assigment is a statement' Not any more it isn't. We've now gone from discussion to bitter recriminations *wink* I don't see any recrimination in what either said. "del is a statement" -- yes, granted "function and class declarations are statements" -- class, yes, but you have "def" and "lambda" as statement and expression equivalents. Even class can be re-written as a call to type(), if you need to. It's probably not practical to do so in anything but the simplest cases, but it is there. Serhiy's viewpoint is a legitimate one. A major difference between def, class, and import statements and equivalent lambda, type, and __import__ expressions is that the latter do not name-bind the resulting object. This will continue to be true. There is, however, precedent for subverting "assignment is a statement". >>> class C(): pass >>> c = C() >>> c.a = 1 >>> setattr(c, 'b', 2) >>> c.b 2 However, the target name, when given explicitly, is quoted. This preserves the general rule that non-keyword identifiers in expressions are immediately evaluated. The current exceptions are the 'and', 'or', and 'if-else' constructs that embed flow control in expressions. But if a name in such expressions is not ignored, it is evaluated normally. The purpose of setattr is to allow the target attribute name to be any variable or expression that evaluates to a string, so that one can do the following. >>> d = 'c' >>> setattr(c, d+'2', 3) >>> c.c2 3 or even >>> setattr(c, input('aname: '), 33) aname: qr >>> c.qr 33 (An allowed side-effect is the possibility of adding attributes, such as '2e', that can only be recovered with getattr.) The same comments apply to globals().update({'foo':42}), pointed out by David Merz in another post. (This specific form does not work does not work within functions, as pointed out by Chris Angelico. But others do.) A major difference between a while loop statement and an equivalent tail recursion call (expression) is that while loops do explicit assignment in the current namespace while recursive calls do implicit assignment in a new (and unneeded) execution frame. The targets are the unquoted parameter names in the function header. I regard the the easy use of unevaluated unquoted names as a justification for having statements in addition to expressions. An alternate assignment-within-expressions proposal would be to follow the setattr precedent. Add a builtin function 'set' with paramenters 'name' and 'value'. It would have to be built-in because Python code cannot directly access function local namespaces. The problem, aside from extra typing, is that efficient implementation of functions requires that all local names be known at compile time. But a name added by "set(input('name: '), )" is impossible to know. Making the assignment target be an unquoted unevaluated non-keyword name immediately followed by ':=' solves this. But it either introduces a new and different type of exception to 'names in expressions are evaluated', or one must regard 'assignment expression' as a new statement-expression hybrid. Advocates of assignment expressions should not really be surprised that this disquiets some people. -- Terry Jan Reedy ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 08:32:32PM +0200, Sven R. Kunze wrote: > >>while total != (total := total + term): > >> term *= mx2 / (i*(i+1)) > >> i += 2 > >>return total > > This very example here caught my eye. > > Isn't total not always equal to total? What would "regular" Python have > looked like? Read the Appendix to the PEP: https://github.com/python/peps/blob/master/pep-0572.rst And no, total is not always not equal to total. When total and term are sufficiently different, total+term underflows to just total, and the loop exits. py> total = 1.5e30 py> term = 12.5 py> total + term != total False I read it as: while total != updated total: do stuff and find it easier to follow than having to juggle the extra book-keeping "old" variable in the original code. YMMV. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018, 09:09 Steven D'Aprano wrote: > On Wed, Jul 04, 2018 at 12:10:11AM -0700, Nathaniel Smith wrote: > > > Right, Python has a *very strong* convention that each line should > > have at most one side-effect, > > import math, fractions, decimal > > (PEP 8 be damned, sometimes, especially in the REPL, this is much > better than three separate imports.) > Sure, the nice thing about "very strong convention" versus "strict rule" is that there's a bit of lee-way at the edges. I'm pretty sure PEP 572 would not be accepted if it's proponents were expecting it to be forbidden by PEP 8 though. > values = [mapping.pop(key) for key in (1, 3, 6, 15)] > > Admittedly, that's an awfully specific case. But would you really > re-write that as: > > values = [mapping.pop(1)] > values.append(mapping.pop(3) > values.append(mapping.pop(6) > values.append(mapping.pop(15) > > just to keep the "one side-effect per line" rule? I wouldn't. > I don't think I've ever seen something like this in real life, but sure, I'd say it's pushing the edge of good taste, but maybe just squeaking under the line. A more common edge case for my rule would be: x = d.pop() where one could argue that this is doing two things: (1) removing an item from a container, and (2) storing it in a variable. But that's ok for me argument, because my argument is about how people represent the code in their mind so they can reason about it, and "take a value from *here* and put it *there*" is still simple enough to feel like a single operation, and there's no possibility of confusion about what order things happen in. "Import these three modules" is similar. This is also why I'm ok with if x := fn(): But my mind stack-overflows when trying to read if (x := fn()) is None: The first is a complex operation, that both triggers a jump and mutates a variable, which is two side-effects. But the two side-effects are closely linked and cannot affect each other, so I can think of it as one "save and jump" operation. In the second case, there's clearly 3 separate phases that I have to simulate in my head: first the mutation of 'x', then switching back to expression evaluation to do the comparison with None, and then the 'if'. And of course it gets much worse in the PEPs motivating examples, where a variable is created and used within the same expression. This is a whole mode of reasoning about code that python has never required before (in practice), and even if you think := is fabulous you should still at least be able to acknowledge that this is a huge shift. > Anyway, since "one side-effect per line" is just a convention, there's > absolutely no reason why it cannot remain a convention. Don't do this: > > values = (x := expensive_func(1, 2))+(y := expensive_func(3, 4)) + x*y > > unless you really have to. It's just common sense. > I think this really underestimates the importance of this kind of convention in how people learn and use the language, and how the language and it's conventions influence each other. If list.sort returned self, then people would absolutely write things like mylist.sort().reverse() And then we'd have lint rules and arguments about it and we'd have to waste precious brain power deciphering this in other people's code and arguing about it in code reviews. By not returning 'self', the language clearly takes a position that you shouldn't do this, and cuts off all that discussion. The := operator is exactly the opposite: it's *only purpose* is to break this convention, which is a pretty strong statement that now we are supposed to embed side effects inside expressions, and be prepared to read code that does this. > Conventions are good. If they'e enough to stop people writing: > > mylist = mylist.sort() or mylist.reverse() or mylist > > they'll be good enough to stop people stuffing every line full of > assignment expressions. > > > > > and that if it does have a side-effect > > it should be at the outermost level. > > I don't understand what that means. Do you mean the global scope? > I mean something like "the top node of the statement's AST". A normal statement: print([a]) Technically only one side-effect in this line, but it's in a weird place: [print(a)] > > I think the most striking evidence for this is that during the > > discussion of PEP 572 we discovered that literally none of us – > > including Guido – even *know* what the order-of-evaluation is inside > > expressions. > > I'm not sure that "literally none of us" is quite true, after all the > code is deterministic and well-defined and surely whoever maintains it > probably understands it, but even if it were true, I don't see the > connection between "we don't know the order of operations" and "Python > has a rule no more than one-side effect per line". Seems a pretty > tenuous ccomclusion to draw. > Side-effects and sequencing are intimately linked. When you have side-effects, you have to think about their order; contrariwise, in pure code, ord
Re: [Python-Dev] Examples for PEP 572
Sorry for adding yet another mail. :-( On 04.07.2018 10:54, Serhiy Storchaka wrote: Sorry, this PEP was rewritten so many times that I missed your Appendix. while total != (total := total + term): term *= mx2 / (i*(i+1)) i += 2 return total This very example here caught my eye. Isn't total not always equal to total? What would "regular" Python have looked like? Regards, Sven ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, Jul 3, 2018 at 11:52 PM Chris Angelico wrote: > On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka > wrote: > > I believe most Python users are not > > professional programmers -- they are sysadmins, scientists, hobbyists and > > kids -- > > [citation needed] > Let's focus on France: 1) there are ~800 000 person aged 15. (Source: https://www.insee.fr/fr/statistiques/1892088?sommaire=1912926 ) 2) 40% of these are pupils in the "filière générale" (Source: https://fr.wikipedia.org/wiki/Baccalaur%C3%A9at_en_France#Statistiques ). 3) Since 2017, Python is the language used to teach algorithmics to these pupils. => We can conclude that there are at least 320 000 pupils learning Python this year, and safely assume that most of them are not "professional programmers". Note also that this number is accretive (i.e.: 320 000 this year, 640 000 next year, etc.). 4) The annual turnover for the IT sector in France (including: software vendor, service and consulting) was 54 billions euros in 2017. This probably translates to around or less than 600 000 IT professionals. How many of them are developers ? I have no idea, but I'm sure it's less that 50%. How many of them are developing professionally in Python ? I have no idea, I'd guess less than 10%, but let's assume 20%. => This gives less than 60 000 professional Python programmers in France. Probably much less. Conclusion: there are probably more than 5 times more non professional Python programmers in France (counting only the high-school pupils, not other categories such as their teachers, but also scientist, sysadmins or hobbyist) than professional programmers. Next year it will be (more than) 1 to 10. The year after that, 1 to 15, etc. S. -- Stefane Fermigier - http://fermigier.com/ - http://twitter.com/sfermigier - http://linkedin.com/in/sfermigier Founder & CEO, Abilian - Enterprise Social Software - http://www.abilian.com/ Chairman, Free&OSS Group @ Systematic Cluster - http://www.gt-logiciel-libre.org/ Co-Chairman, National Council for Free & Open Source Software (CNLL) - http://cnll.fr/ Founder & Organiser, PyParis & PyData Paris - http://pyparis.org/ & http://pydata.fr/ ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 2:16 PM Tim Peters wrote: > > [Yury Selivanov] > > Wow, I gave up on this example before figuring this out (and I also > > > stared at it for a good couple of minutes). Now it makes sense. It's > > > funny that this super convoluted snippet is shown as a good example > > > for PEP 572. Although almost all PEP 572 examples are questionable. > > And another who didn't actually read the PEP Appendix. See my reply just > before this one: yes, the Appendix gave that as a good example, but as a > good example of assignment-expression ABUSE. The opposite of something > desirable. > > I've never insisted there's only one side to this, and when staring at code > was equally interested in cases where assignment expressions would hurt as > where they would help. I ended up giving more examples where they would > help, because after writing up the first two bad examples in the Appendix > figured it was clear enough that "it's a bad idea except in cases where it > _obviously_ helps". > > Same way, e.g., as when list comprehensions were new, I focused much more on > cases where they might help after convincing myself that a great many nested > loops building lists were much better left _as_ nested loops. So I looked > instead for real-code cases where they would obviously help, and found plenty. > > And I'm really glad Python added listcomps too, despite the possibility of > gross abuse ;-) Thank you for the clarification, Tim. I agree, list comprehensions can indeed be abused and we all see that happening occasionally. However, assignment expressions make it easy (almost compelling) to push more logic even to simple comprehensions (with one "for" / one "if"). You probably understand why most core devs are irritated with the PEP: the majority thinks that the potential of its abuse can't be compared to any other Python syntax. It's sad that the PEP doesn't really address that except saying "This is a tool, and it is up to the programmer to use it where it makes sense, and not use it where superior constructs can be used." Well, to those of use who routinely review code written by people who aren't proficient Python coders (read most people working at Google, Facebook, Dropbox, Microsoft, or really any company) this argument is very weak. In other words: I'm looking forward to reviewing clever code written by clever people. Spending extra time arguing if a snippet is readable or not should be fun and productive, right? :) Disabling := as a company-wide policy will probably be the only way out. Yury ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 12:36 PM Stéfane Fermigier wrote: > > And dissimilar to countries where CS is not taught in schools, or another > language is used (Scratch or other block-languages are usually popular). > Just found: https://www.ibtimes.co.uk/coding-uk-classroom-python-overtakes-french-most-popular-language-primary-schools-1517491 :) as a pythonista. :( as a frenchman Also, not sure how that translates into raw numbers. S. -- Stefane Fermigier - http://fermigier.com/ - http://twitter.com/sfermigier - http://linkedin.com/in/sfermigier Founder & CEO, Abilian - Enterprise Social Software - http://www.abilian.com/ Chairman, Free&OSS Group @ Systematic Cluster - http://www.gt-logiciel-libre.org/ Co-Chairman, National Council for Free & Open Source Software (CNLL) - http://cnll.fr/ Founder & Organiser, PyParis & PyData Paris - http://pyparis.org/ & http://pydata.fr/ ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 04/07/2018 02:54, Terry Reedy wrote: The 2-argument form of iter is under-remembered and under-used. The length difference is 8. while (command := input("> ")) != "quit": for command in iter(lambda: input("> "), "quit"): A general principle that Chris Angelico has repeatedly mention applies here: If you want (as I instinctively would) while (command := input("> ")).lower() != "quit": you can't express that in your iter version. Regards Rob Cliffe ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
Forwarding the reply to the list. Accidentally pressed the wrong button and sent this message personally to Serhiy. Sorry :) ср, 4 июл. 2018 г. в 11:57, Serhiy Storchaka : > > 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(shallow)copyable object of type %s" % cls) > > I was going to rewrite this code as > > reductor = dispatch_table.get(cls) > if reductor: > rv = reductor(x) > else: > rv = x.__reduce_ex__(4) > > There were reasons for the current complex code in Python 2, but now > classic classes are gone, and every class has the __reduce_ex__ method > which by default calls __reduce__ which by default is inherited from > object. With that simplification the benefit of using ":=" in this > example looks less impressed. > > Yes you are right with this particular snippet (in its current version, it is an echo from Python 2). But I think you have missed the general idea: The logic of this code is flat (like a switch) but the visual structure is pretty nested. That is why (maybe just for me) there is a mental imbalance in perception. And this type of code is rather common. Therefore, for me, the main gain from using the assignment expression in these patterns of code is that the visual syntax emphasizes the semantics. To be honest, I do not see any benefit of usage of assignment expression outside `if` and `while` headers, but if others do see let it be so. With kind regards, -gdg ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 08:33:17PM +0300, Ivan Pozdeev via Python-Dev wrote: > >>while total != (total := total + term): > >> term *= mx2 / (i*(i+1)) > >> i += 2 > >>return total [...] > It took me a few minutes to figure out that this construct actually > checks term == 0. That's badly wrong. Hint: it's floating point code. total and term are floats, so things like this are possible: py> total = 9.5e95 py> term = 1.2 py> total + term == total True As you can see, term is nothing even close to zero. > So, this example abuses the construct to do something it's not designed > to do: perform an unrelated operation before checking the condition. Well, that's one opinion. > (Cue attempts to squeeze ever mode code here.) I would fail it in review. Okay. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
[Yury Selivanov] > Wow, I gave up on this example before figuring this out (and I also > > stared at it for a good couple of minutes). Now it makes sense. It's > > funny that this super convoluted snippet is shown as a good example > > for PEP 572. Although almost all PEP 572 examples are questionable. And another who didn't actually read the PEP Appendix. See my reply just before this one: yes, the Appendix gave that as a good example, but as a good example of assignment-expression ABUSE. The opposite of something desirable. I've never insisted there's only one side to this, and when staring at code was equally interested in cases where assignment expressions would hurt as where they would help. I ended up giving more examples where they would help, because after writing up the first two bad examples in the Appendix figured it was clear enough that "it's a bad idea except in cases where it _obviously_ helps". Same way, e.g., as when list comprehensions were new, I focused much more on cases where they might help after convincing myself that a great many nested loops building lists were much better left _as_ nested loops. So I looked instead for real-code cases where they would obviously help, and found plenty. And I'm really glad Python added listcomps too, despite the possibility of gross abuse ;-) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 10:13:15AM -0700, Devin Jeanpierre wrote: > > > In Python it'd look like this: > > > > > > if x = expr(); x < 0: > > > do_stuff() [...] > > Python's parser is restricted to LL(1) by design, so treating semicolons > > in "if" statements as a special case might not even be possible. > > But even if it is possible, not only would this special case > > break the Zen, but it would be UGLY too. > > It isn't a special case, and it's still LL(1). Once you encounter an > "if", you parse n simple statements separated by a ";", until you > reach a colon. I'll take your word about the LL(1). Did you actually mean arbitrary simple statements? if import math; mylist.sort(); print("WTF am I reading?"); True: pass A more reasonable suggestion would be to only allow *assignments*, not arbitrary simple statements. But that's another special case: - everywhere else where a semicolon is legal, it can separate arbitrary simple statements; - except inside an if clause, where only assignments are allowed. > I don't understand why you think this is "clearly" a syntax error. Taking the principle that semicolons separate statements, you have an if statement if condition: with one or more semicolon-separated statements between the "if" and the condition: if statement; statement; condition: If we stick to the rule that semicolons separate statements, that means we have: if statement # SyntaxError statement # okay condition:# SyntaxError If we don't want that, we need a new rule to treat semicolons differently inside if statements that they're treated elsewhere. If we applied this rule "allow statements separated by semicolons" everywhere, we'd get this: # I trust you don't want anything even close to these from x=1; sys import y=2; argv data x=1; y=2; = sorted(data) raise x=1; y=2; Exception as err: So we have to treat semicolons inside if statements differently from semicolons everywhere else. That what I meant by saying it would be a special case. The beauty of assignment expressions is that they AREN'T a special case. Being an expression, they're legal anywhere any other expression is allowed, and illegal anywhere where expressions aren't allowed. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
[Serhiy Storchaka] > > Sorry, this PEP was rewritten so many times that I missed your > [Tim's] Appendix. > > > >> while total != (total := total + term): > >> term *= mx2 / (i*(i+1)) > >> i += 2 > >> return total > > > > This code looks clever that the original while loop with a break in a > > middle. I like clever code. But it needs more mental efforts for > > understanding it. > > > > I admit that this is a good example. > > > > There is a tiny problem with it (and with rewriting a while loop as a > > for loop, as I like). Often the body contains not a single break. In > > this case the large part of cleverness is disappeared. :-( [Ivan Pozdeev] > It took me a few minutes to figure out that this construct actually > > checks term == 0. > > > > So, this example abuses the construct to do something it's not designed > > to do: perform an unrelated operation before checking the condition. > > (Cue attempts to squeeze ever mode code here.) I would fail it in review. > > > > This "clever" code is exactly what Perl burned itself on and what > > Python, being its antithesis, was specifically designed to avoid. So you didn't read the PEP Appendix at all, and Serhiy did but apparently skipped reading what the PEP _said_ about that example. It was clearly identified as abuse: a case in which using assignment expressions made the code significantly WORSE. I gave examples of both "wins" and "losses" while staring at real code - I wasn't searching for "proof" that a pre-determined conclusion was justified. So I wholly agree with you (Ivan) about that example - and that it struck Serhiy as a good example convinces me more than before that there's no overlap in the ways Serhiy and I view this part of the world ;-) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 1:35 PM Ivan Pozdeev via Python-Dev wrote: > > On 04.07.2018 11:54, Serhiy Storchaka wrote: > >> while total != (total := total + term): > >> term *= mx2 / (i*(i+1)) > >> i += 2 > >> return total > > > > This code looks clever that the original while loop with a break in a > > middle. I like clever code. But it needs more mental efforts for > > understanding it. > > > > I admit that this is a good example. > > > > There is a tiny problem with it (and with rewriting a while loop as a > > for loop, as I like). Often the body contains not a single break. In > > this case the large part of cleverness is disappeared. :-( > > It took me a few minutes to figure out that this construct actually > checks term == 0. Wow, I gave up on this example before figuring this out (and I also stared at it for a good couple of minutes). Now it makes sense. It's funny that this super convoluted snippet is shown as a good example for PEP 572. Although almost all PEP 572 examples are questionable. Yury ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 04.07.2018 11:54, Serhiy Storchaka wrote: 04.07.18 10:06, Tim Peters пише: [Tim] >> I really don't know what Guido likes best about this, but for me it's >> the large number of objectively small wins in `if` and `while` >> contexts. They add up. That conclusion surprised me. That there are >> occasionally bigger wins to be had is pure gravy. [Serhiy Storchaka] > Could you please show me several examples in real code? I > have not seen any win yet. My PEP Appendix was derived entirely from looking at real code. If you don't believe the examples I showed there are wins (and I don't know whether you've seen them, because your original message in this thread only echoed examples from the body of the PEP), then what we each mean by "win" in this context has no intersection, so discussing it would be futile (for both of us). Sorry, this PEP was rewritten so many times that I missed your Appendix. while total != (total := total + term): term *= mx2 / (i*(i+1)) i += 2 return total This code looks clever that the original while loop with a break in a middle. I like clever code. But it needs more mental efforts for understanding it. I admit that this is a good example. There is a tiny problem with it (and with rewriting a while loop as a for loop, as I like). Often the body contains not a single break. In this case the large part of cleverness is disappeared. :-( It took me a few minutes to figure out that this construct actually checks term == 0. So, this example abuses the construct to do something it's not designed to do: perform an unrelated operation before checking the condition. (Cue attempts to squeeze ever mode code here.) I would fail it in review. This "clever" code is exactly what Perl burned itself on and what Python, being its antithesis, was specifically designed to avoid. if result := solution(xs, n): # use result It looks equally clear with the original code. This is not enough for introducing a new syntax. 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(shallow)copyable object of type %s" % cls) I was going to rewrite this code as reductor = dispatch_table.get(cls) if reductor: rv = reductor(x) else: rv = x.__reduce_ex__(4) There were reasons for the current complex code in Python 2, but now classic classes are gone, and every class has the __reduce_ex__ method which by default calls __reduce__ which by default is inherited from object. With that simplification the benefit of using ":=" in this example looks less impressed. if (diff := x - x_base) and (g := gcd(diff, n)) > 1: return g while a > (d := x // a**(n-1)): a = ((n-1)*a + d) // n return a I would have a fun writing such code. As well as I believe you had a fun writing it. But I suppose the original code is simpler for a casual reader, and I will refrain from using such code in a project maintained by other people (in particular in the Python stdlib). Which is what I expect: the treatment you gave to the examples from the body of the PEP suggests you're determined not to acknowledge any "win", however small. I have to admit that *there are* examples that can have a small win. I wondering why your examples are not used in the PEP body instead of examples which play *against* PEP 572. Yet a win too small to me for justifying such syntax change. I know that I can not convince you or Guido. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/vano%40mail.mipt.ru -- Regards, Ivan ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 6:36 AM Steven D'Aprano wrote: > > On Wed, Jul 04, 2018 at 01:03:02AM -0700, Devin Jeanpierre wrote: > > > The PEP doesn't talk about it, but FWIW, Go and C++17 if statements > > allow you to put arbitrary simple statements in the suite header, and > > by doing that, solves all the issues you and the PEP mentioned. > > Whether they solve "all the issues" discussed in the PEP is doubtful, > since they're entirely limited to just if statements. The only issue that PEP 572 has with limiting to if statements is: "Disadvantages: Answers only a fraction of possible use-cases, even in if/whilestatements." The Go/C++17 syntax resolves that (while still being limited to if statements and while statements -- the primary use cases AFAIK, and the only ones Nathaniel agrees with). > > In Python it'd look like this: > > > > if x = expr(); x < 0: > > do_stuff() > > > That's even more doubtful, since the semicolon in Python already has a > meaning of separating statements on a line. That could be equivalent to: > > if x = expr() > x < 0: > do_stuff() > > which would clearly have to be a syntax error. *Two* syntax errors. > > Python's parser is restricted to LL(1) by design, so treating semicolons > in "if" statements as a special case might not even be possible. > But even if it is possible, not only would this special case > break the Zen, but it would be UGLY too. It isn't a special case, and it's still LL(1). Once you encounter an "if", you parse n simple statements separated by a ";", until you reach a colon. Where LL(1) runs into trouble is that last statement must be an Expr statement, but that can be checked after parsing (e.g. during compilation). I don't understand why you think this is "clearly" a syntax error. (So is ":=", if you restrict yourself to the current Python syntax.) As for ugly... well, compare: while (kv := x.pop())[0] is not None: foo(kv[1]) while k, v = x.pop(); k is not None: foo(v) if (v := d[k]) == _EOF: return None if v = d[k]; v == _EOF: return None I like ":=" when it is the only thing in the expression: "if a:= b:" etc. Every other time I would prefer C++/Go's syntax. -- Devin ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 12:13 PM Steven D'Aprano wrote: > On Wed, Jul 04, 2018 at 10:20:35AM -0400, David Mertz wrote: > > Hmmm... I admit I didn't expect quite this behavior. I'm don't actually > > understand why it's doing what it does. > > > > >>> def myfun(): > > ...print(globals().update({'foo', 43}), foo) > > Try it with a dict {'foo': 43} instead of a set :-) > I think Chris meant to try it inside a function using locals() rather > than globals. Ah... you say "tomato" I say "raspberry"... set, dict... Yeah, typo fixed, it makes more sense. Still, even a `globals().update()` expression is a binding operation. But it works perfectly fine with locals() also :-): >>> def myfun(): ...print(locals().update({'foo': 44}), locals().get('foo')) ... >>> myfun() None 44 -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 10:20:35AM -0400, David Mertz wrote: > Hmmm... I admit I didn't expect quite this behavior. I'm don't actually > understand why it's doing what it does. > > >>> def myfun(): > ...print(globals().update({'foo', 43}), foo) Try it with a dict {'foo': 43} instead of a set :-) > ... > >>> myfun() > Traceback (most recent call last): > File "", line 1, in > File "", line 2, in myfun > TypeError: cannot convert dictionary update sequence element #0 to a > sequence I think Chris meant to try it inside a function using locals() rather than globals. > That said, this is a silly game either way. And even though you CAN > (sometimes) bind in an expression pre-572, that's one of those perverse > corners that one shouldn't actually use. Still, it is sometimes useful to explore scoping issues by using globals() and/or locals() to see what happens. But I would really hesitate to use them in production unless I was really careful. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 12:10:11AM -0700, Nathaniel Smith wrote: > Right, Python has a *very strong* convention that each line should > have at most one side-effect, import math, fractions, decimal (PEP 8 be damned, sometimes, especially in the REPL, this is much better than three separate imports.) values = [mapping.pop(key) for key in (1, 3, 6, 15)] Admittedly, that's an awfully specific case. But would you really re-write that as: values = [mapping.pop(1)] values.append(mapping.pop(3) values.append(mapping.pop(6) values.append(mapping.pop(15) just to keep the "one side-effect per line" rule? I wouldn't. Anyway, since "one side-effect per line" is just a convention, there's absolutely no reason why it cannot remain a convention. Don't do this: values = (x := expensive_func(1, 2))+(y := expensive_func(3, 4)) + x*y unless you really have to. It's just common sense. Conventions are good. If they'e enough to stop people writing: mylist = mylist.sort() or mylist.reverse() or mylist they'll be good enough to stop people stuffing every line full of assignment expressions. > and that if it does have a side-effect > it should be at the outermost level. I don't understand what that means. Do you mean the global scope? > I think the most striking evidence for this is that during the > discussion of PEP 572 we discovered that literally none of us – > including Guido – even *know* what the order-of-evaluation is inside > expressions. I'm not sure that "literally none of us" is quite true, after all the code is deterministic and well-defined and surely whoever maintains it probably understands it, but even if it were true, I don't see the connection between "we don't know the order of operations" and "Python has a rule no more than one-side effect per line". Seems a pretty tenuous ccomclusion to draw. > In fact PEP 572 now has a whole section talking about the > oddities that have turned up here so far, and how to fix them. Which > just goes to show that even its proponents don't actually think that > anyone uses side-effects inside expressions, because if they did, then > they'd consider these changes to be compatibility-breaking changes. If you're talking about fixing the scoping issues inside classes, that's no longer part of the PEP (although the current version hasn't been updated to reflect that). The weirdness of class scopes already exist. This might, at worst, make it more visible, but it isn't going to make the problem worse. If you're talking about something else, I can't think of what it might be. Can you explain? > Some people make fun of Python's expression/statement dichotomy, > because hey don't you know that everything can be an expression, > functional languages are awesome hurhur, Oh, you mean functional languages like Rust, Javascript, and Ruby? (Or at least, *almost* everything is an expression.) The functional programming paradigm is a lot more than just "everything is an expression", and very much *non*-functional languages like Javascript can be designed to treat everything as an expression. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, 4 Jul 2018 09:43:04 -0300 Brett Cannon wrote: > > I think this is a very key point that the "this is bad" crowd is > overlooking. Even if this syntax turns out to not be that useful, abusing > the walrus operator can be fixed with a comment of "hard to follow; please > simplify" without teaching any new concepts or idioms The same could be said of any language mis-feature. Do we want to claim that questionable semantics in Javascript and PHP are not a problem, because the bad constructs can simply be turned away in code review? That sounds like a modern re-phrasing of the old argument, """C is not dangerous in itself, it's only the fault of incompetent programmers""". Just replace "incompetent programmers" with "complacent reviewers"... > Another point is we live in a dictatorship by choice, and yet some people > seem very upset our dictator dictated in the end. Not sure what you mean with "by choice". When I arrived here, I certainly wasn't asked whether I wanted the place to be a dictatorship or not ;-) Granted, I did choose to come here, but not because of a personal appeal for dictatorship. One could claim that the qualities of Python are due to it being a dictatorship. I think it's impossible to answer that question rigorously, and all we're left with is our personal feelings and biases on the subject. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
Hmmm... I admit I didn't expect quite this behavior. I'm don't actually understand why it's doing what it does. >>> def myfun(): ...print(globals().update({'foo', 43}), foo) ... >>> myfun() Traceback (most recent call last): File "", line 1, in File "", line 2, in myfun TypeError: cannot convert dictionary update sequence element #0 to a sequence That said, this is a silly game either way. And even though you CAN (sometimes) bind in an expression pre-572, that's one of those perverse corners that one shouldn't actually use. On Wed, Jul 4, 2018 at 9:58 AM Chris Angelico wrote: > On Wed, Jul 4, 2018 at 11:52 PM, David Mertz wrote: > > On Wed, Jul 4, 2018 at 3:02 AM Chris Angelico wrote: > >> > >> "Assignment is a statement" -- that's exactly the point under > discussion. > >> "del is a statement" -- yes, granted > >> "function and class declarations are statements" -- class, yes, but > >> you have "def" and "lambda" as statement and expression equivalents. > >> "import is a statement" -- but importlib.import_module exists for a > reason > >> > >> I'm going to assume that your term "mutating" there was simply a > >> miswording, and that you're actually talking about *name binding*, > >> which hitherto occurs only in statements. Yes, this is true. > > > > > > Nope, not actually: > > > del foo > print(globals().update({'foo':42}), foo) > > None 42 > > > > Try it inside a function though. > > ChrisA > ___ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/mertz%40gnosis.cx > -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 11:52 PM, David Mertz wrote: > On Wed, Jul 4, 2018 at 3:02 AM Chris Angelico wrote: >> >> "Assignment is a statement" -- that's exactly the point under discussion. >> "del is a statement" -- yes, granted >> "function and class declarations are statements" -- class, yes, but >> you have "def" and "lambda" as statement and expression equivalents. >> "import is a statement" -- but importlib.import_module exists for a reason >> >> I'm going to assume that your term "mutating" there was simply a >> miswording, and that you're actually talking about *name binding*, >> which hitherto occurs only in statements. Yes, this is true. > > > Nope, not actually: > del foo print(globals().update({'foo':42}), foo) > None 42 > Try it inside a function though. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 3:02 AM Chris Angelico wrote: > "Assignment is a statement" -- that's exactly the point under discussion. > "del is a statement" -- yes, granted > "function and class declarations are statements" -- class, yes, but > you have "def" and "lambda" as statement and expression equivalents. > "import is a statement" -- but importlib.import_module exists for a reason I'm going to assume that your term "mutating" there was simply a > miswording, and that you're actually talking about *name binding*, > which hitherto occurs only in statements. Yes, this is true. > Nope, not actually: >>> del foo >>> print(globals().update({'foo':42}), foo) None 42 -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 05:02:07PM +1000, Chris Angelico wrote: > On Wed, Jul 4, 2018 at 4:07 PM, Serhiy Storchaka wrote: > "Assignment is a statement" -- that's exactly the point under discussion. Not any more it isn't. We've now gone from discussion to bitter recriminations *wink* > "del is a statement" -- yes, granted > > "function and class declarations are statements" -- class, yes, but > you have "def" and "lambda" as statement and expression equivalents. Even class can be re-written as a call to type(), if you need to. It's probably not practical to do so in anything but the simplest cases, but it is there. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 04, 2018 at 01:03:02AM -0700, Devin Jeanpierre wrote: > The PEP doesn't talk about it, but FWIW, Go and C++17 if statements > allow you to put arbitrary simple statements in the suite header, and > by doing that, solves all the issues you and the PEP mentioned. Whether they solve "all the issues" discussed in the PEP is doubtful, since they're entirely limited to just if statements. It amuses me that the Go designers -- presumably Rob Pike -- decided on a rule "no assignment expressions", and then immediately broke it "well okay, assignment expressions in if statements". At least Guido waited 20+ years to change his mind :-) > In Python it'd look like this: > > if x = expr(); x < 0: > do_stuff() That's even more doubtful, since the semicolon in Python already has a meaning of separating statements on a line. That could be equivalent to: if x = expr() x < 0: do_stuff() which would clearly have to be a syntax error. *Two* syntax errors. Python's parser is restricted to LL(1) by design, so treating semicolons in "if" statements as a special case might not even be possible. But even if it is possible, not only would this special case break the Zen, but it would be UGLY too. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, Jul 03, 2018 at 03:24:09PM -0700, Chris Barker via Python-Dev wrote: > Over the years I've been using it (most of its life), Python has evolved to > become much less of a "scripting" language, and much more of a "systems" > language, and this addition is a (pretty significant) step more in that > direction. As I understand it, the most commonly accepted definitions are: Systems language: low-level languages designed to compile down to efficient machine code, suitable for writing operating systems, device drivers, and code for embedded systems. Application language: high-level language intended to insulate the programmer from the gory details of memory management, suitable for writing user-space applications. Scripting language: any interpreted high-level language the speaker doesn't like *wink* https://en.wikipedia.org/wiki/System_programming_language See also Ousterhout's (false) dichotomy: https://en.wikipedia.org/wiki/Ousterhout's_dichotomy Python is certainly not a systems language in the sense of C, Ada or Rust. It could be classified as an application language, like Java. And it still remains an awesome glue language for C and Fortran code. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, Jul 3, 2018, 22:27 Tim Peters, wrote: > [INADA Naoki] > > ... > > On the other hand, I understand PEP 572 allows clever code > > simplifies tedious code. It may increase readability of non-dirty > code. > > The latter is the entire intent ,of course. We can't force people to > write readable code, but I don't understand the widespread assumption that > other programmers are our enemies who have to be preemptively disarmed ;-) > > Use code review to enforce readable code. If you want a coding standard > here, use mine: "if using an assignment expression isn't obviously better > (at least a little so), DON'T USE IT". That's the same standard I use for > lots of things (e.g., is such-&-such better as a listcomp or as nested > loops?). It only requires that you have excellent taste in what "better" > means ;-) > I think this is a very key point that the "this is bad" crowd is overlooking. Even if this syntax turns out to not be that useful, abusing the walrus operator can be fixed with a comment of "hard to follow; please simplify" without teaching any new concepts or idioms (and which happens with constructs most of us would agree are useful and well-designed). IOW when I'm doing code reviews for folks this is not going to be what I stress about or spill the most characters trying to explain how to fix. > As I noted in the PEP's Appendix A, I refuse to even write code like > > i = j = count = nerrors = 0 > > because it squashes conceptually distinct things into a single statement > . I'll always write that as > > i = j = 0 > count = 0 > nerrors = 0 > > instead - or even in 4 lines if `i` and `j` aren't conceptually related. > > That's how annoyingly pedantic I can be ;-) Yet after staring at lots of > code, starting from a neutral position (why have an opinion about anything > before examination?), I became a True Believer. > > I really don't know what Guido likes best about this, but for me it's the > large number of objectively small wins in `if` and `while` contexts. They > add up. That conclusion surprised me. That there are occasionally bigger > wins to be had is pure gravy. > Another point is we live in a dictatorship by choice, and yet some people seem very upset our dictator dictated in the end. 😉 Rather than being upset that Guido chose not to heed some advice that someone personally thought was crucial, I'm going to rely on the point that all the salient points were made (albeit sometimes in sensationalist terms in what seems like a higher-than-normal frequency), and trust Guido's design taste which I have appreciated for my 18 years as a Python user. -Brett > But in no case did I count "allows greater cleverness" as a win. The > Appendix contains a few examples of "bad" uses too, where cleverness in > pursuit of brevity harms clarity. In fact, to this day, I believe those > examples derived from abusing assignment expressions in real-life code are > more horrifying than any of the examples anyone else _contrived_ to "prove" > how bad the feature is. > > I apparently have more faith that people will use the feature as > intended. Not all people, just most. The ones who don't can be beaten > into compliance, same as with any other abused feature ;-) > > ___ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/brett%40python.org > ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 7:59 PM, Stéfane Fermigier wrote: > > > On Tue, Jul 3, 2018 at 11:52 PM Chris Angelico wrote: >> >> On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka >> wrote: >> > I believe most Python users are not >> > professional programmers -- they are sysadmins, scientists, hobbyists >> > and >> > kids -- >> >> [citation needed] > > > Let's focus on France: > > 1) there are ~800 000 person aged 15. (Source: > https://www.insee.fr/fr/statistiques/1892088?sommaire=1912926 ) > > 2) 40% of these are pupils in the "filière générale" (Source: > https://fr.wikipedia.org/wiki/Baccalaur%C3%A9at_en_France#Statistiques ). > > 3) Since 2017, Python is the language used to teach algorithmics to these > pupils. > > => We can conclude that there are at least 320 000 pupils learning Python > this year, and safely assume that most of them are not "professional > programmers". > > Note also that this number is accretive (i.e.: 320 000 this year, 640 000 > next year, etc.). > > 4) The annual turnover for the IT sector in France (including: software > vendor, service and consulting) was 54 billions euros in 2017. This probably > translates to around or less than 600 000 IT professionals. How many of them > are developers ? I have no idea, but I'm sure it's less that 50%. How many > of them are developing professionally in Python ? I have no idea, I'd guess > less than 10%, but let's assume 20%. > > => This gives less than 60 000 professional Python programmers in France. > Probably much less. > > Conclusion: there are probably more than 5 times more non professional > Python programmers in France (counting only the high-school pupils, not > other categories such as their teachers, but also scientist, sysadmins or > hobbyist) than professional programmers. > > Next year it will be (more than) 1 to 10. The year after that, 1 to 15, etc. Even assuming your figures to be 100% accurate, I don't think you can accept that scaling. Are you claiming that every high school student (a) continues to use Python forever, and (b) continues to use it at a non-professional level? I find that highly unlikely. I'm pretty dubious that these figures will correspond to the rest of the world, where you can't expect that every single high school student is using Python. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
2018-07-04 9:58 GMT+02:00 Serhiy Storchaka :> 04.07.18 05:42, Steven D'Aprano пише: >> There is a deferred feature request to optimize "for x in [item]" as >> equivalent to "for x in (item,)", to avoid constructing a list: >> >> https://bugs.python.org/issue32856 > > > No, this optimization was already made in issue32925. Oh, I missed that optimization: it's even optimized at the AST level, cool! Good job INADA Naoki for the new AST optimizer and Serhiy for this optimization! $ ./python Python 3.8.0a0 (heads/master:97ae32c92e, Jul 4 2018, 09:37:54) >>> import dis; dis.dis('x in [y]') 1 0 LOAD_NAME0 (x) 2 LOAD_NAME1 (y) 4 BUILD_TUPLE 1 6 COMPARE_OP 6 (in) 8 RETURN_VALUE Note: "x in [1]" was already optimized as "x in (1,)" since at least Python 2.7 (in the bytecode peephole optimizer, not at the AST level). Victor ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
04.07.18 10:06, Tim Peters пише: [Tim] >> I really don't know what Guido likes best about this, but for me it's >> the large number of objectively small wins in `if` and `while` >> contexts. They add up. That conclusion surprised me. That there are >> occasionally bigger wins to be had is pure gravy. [Serhiy Storchaka] > Could you please show me several examples in real code? I > have not seen any win yet. My PEP Appendix was derived entirely from looking at real code. If you don't believe the examples I showed there are wins (and I don't know whether you've seen them, because your original message in this thread only echoed examples from the body of the PEP), then what we each mean by "win" in this context has no intersection, so discussing it would be futile (for both of us). Sorry, this PEP was rewritten so many times that I missed your Appendix. while total != (total := total + term): term *= mx2 / (i*(i+1)) i += 2 return total This code looks clever that the original while loop with a break in a middle. I like clever code. But it needs more mental efforts for understanding it. I admit that this is a good example. There is a tiny problem with it (and with rewriting a while loop as a for loop, as I like). Often the body contains not a single break. In this case the large part of cleverness is disappeared. :-( if result := solution(xs, n): # use result It looks equally clear with the original code. This is not enough for introducing a new syntax. 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(shallow)copyable object of type %s" % cls) I was going to rewrite this code as reductor = dispatch_table.get(cls) if reductor: rv = reductor(x) else: rv = x.__reduce_ex__(4) There were reasons for the current complex code in Python 2, but now classic classes are gone, and every class has the __reduce_ex__ method which by default calls __reduce__ which by default is inherited from object. With that simplification the benefit of using ":=" in this example looks less impressed. if (diff := x - x_base) and (g := gcd(diff, n)) > 1: return g while a > (d := x // a**(n-1)): a = ((n-1)*a + d) // n return a I would have a fun writing such code. As well as I believe you had a fun writing it. But I suppose the original code is simpler for a casual reader, and I will refrain from using such code in a project maintained by other people (in particular in the Python stdlib). Which is what I expect: the treatment you gave to the examples from the body of the PEP suggests you're determined not to acknowledge any "win", however small. I have to admit that *there are* examples that can have a small win. I wondering why your examples are not used in the PEP body instead of examples which play *against* PEP 572. Yet a win too small to me for justifying such syntax change. I know that I can not convince you or Guido. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, 3 Jul 2018 15:24:09 -0700 Chris Barker via Python-Dev wrote: > > fair enough, but I think we all agree that *many*, if not most, Python > users are "not professional programmers". While on the other hand everyone > involved in discussion on python-dev and python-ideas is a serious (If not > "professional") programmer. > > So we do have a bit of a disconnect between much of the user base and folks > making decisions about how the language evolves -- which is probably > inevitable, > > Over the years I've been using it (most of its life), Python has evolved to > become much less of a "scripting" language, and much more of a "systems" > language, and this addition is a (pretty significant) step more in that > direction. This change doesn't even make Python a better fit as a systems programming language. Rust's distinguishing feature, after all, isn't that it has an assignment operator. Regards Antoine. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 12:26 AM Nathaniel Smith wrote: > The only cases that seem potentially valuable to me are the ones that > are literally the form 'if := ` and 'while := > '. (I suspect these are the only cases that I would allow in > code that I maintain.) The PEP does briefly discuss the alternative > proposal of restricting to just these two cases, but rejects it > because it would rule out code like 'if ( := ) > '. But those are exactly the cases that I want to > rule out, so that seems like a plus to me :-). The PEP doesn't talk about it, but FWIW, Go and C++17 if statements allow you to put arbitrary simple statements in the suite header, and by doing that, solves all the issues you and the PEP mentioned. In Python it'd look like this: if x = expr(); x < 0: do_stuff() (and presumably, the same for while: "while line = f.readline(); line: ...") -- Devin ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
04.07.18 05:42, Steven D'Aprano пише: On Tue, Jul 03, 2018 at 09:54:22PM -0400, Terry Reedy wrote: results = [(x, y, x/y) for x in input_data for y in [f(x)] if y > 0] Would (f(x),) be faster? There is a deferred feature request to optimize "for x in [item]" as equivalent to "for x in (item,)", to avoid constructing a list: https://bugs.python.org/issue32856 No, this optimization was already made in issue32925. Issue32856 is a different optimization -- it makes such constructions be as fast as a simple assignment. It allows to use an assignment in comprehensions without introducing a new syntax and with zero overhead. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
04.07.18 04:54, Terry Reedy пише: Would (f(x),) be faster? No. Both "for y in [f(x)]" and "for y in (f(x),)" are compiled to the same bytecode. Run your microbenchmarks again, the difference is a small random variation. https://bugs.python.org/issue32925 stuff = [[y := f(x), x/y] for x in range(5)] stuff = [[y, x/y] for x in range(5) for y in [f(x)]] Creating an leaky name binding appears to about 5 x faster than iterating a temporary singleton. With issue32856 be merged, "for var in [expr]" will be compiled to the same bytecode as just "var = expr". This is a simple optimization, and this is a good kind of changes that increase performance for free, without needing users to use a new syntax. It is not merged yet because I have doubts that the need in the assignment inside comprehensions is worth even such small complication of the compiler (of course PEP 572 adds much more complications, and not only to the code generator). If you need to write the above artificial example as a comprehension, lets just merge issue32856. https://bugs.python.org/issue32856 The 2-argument form of iter is under-remembered and under-used. The length difference is 8. while (command := input("> ")) != "quit": for command in iter(lambda: input("> "), "quit"): This doesn't look like a good rationale for such large change as PEP 572. I like the iter version, but the for-loop machinery and extra function call makes a minimal loop half a millisecond slower. import timeit as ti def s(): it = iter(1*'0' + '1') def w(): it = iter(1*'0' + '1') while True: command = next(it) if command == '1': break def f(): it = iter(1*'0' + '1') for command in iter(lambda: next(it), '1'): pass print(ti.timeit('s()', 'from __main__ import s', number=1000)) print(ti.timeit('w()', 'from __main__ import w', number=1000)) print(ti.timeit('f()', 'from __main__ import f', number=1000)) # 0.00097021275 0.936525425001 1.591311794998 Using partial() makes it faster: from functools import partial def p(): it = iter(1*'0' + '1') for command in iter(partial(next, it), '1'): pass print(ti.timeit('s()', 'from __main__ import s', number=1000)) print(ti.timeit('w()', 'from __main__ import w', number=1000)) print(ti.timeit('f()', 'from __main__ import f', number=1000)) print(ti.timeit('p()', 'from __main__ import p', number=1000)) # 0.0016302559961332008 0.7507075049943523 1.3297416319983313 0.6211225209990516 Of course, with added processing of 'command' the time difference disappears. Yes, and this is why I didn't bother about a tiny overhead of a lambda. You can use partial() in a tight performance critical loop. It is even faster than a bare while loop. # Capturing regular expression match objects # See, for instance, Lib/pydoc.py, which uses a multiline spelling # of this effect if match := re.search(pat, text): print("Found:", match.group(0)) # The same syntax chains nicely into 'elif' statements, unlike the # equivalent using assignment statements. elif match := re.search(otherpat, text): print("Alternate found:", match.group(0)) elif match := re.search(third, text): print("Fallback found:", match.group(0)) It may be more efficient to use a single regular expression which consists of multiple or-ed patterns My attempt resulted in a slowdown. Duplicating the dominance of pat over otherpat over third requires, I believe, negative lookahead assertions. I have to admit that *this* example will not get a benefit from rewriting with a single regular expression. I was fooled by the misleading reference to pydoc.py. The code in pydoc.py doesn't have anything common with this example, it searches the first occurrence of the set of patterns in a loop, while the example searches patterns sequentially and only once. The code similar to pydoc.py is common, but I would want to see a real code that corresponds the example in PEP 572. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, Jul 3, 2018 at 11:14 PM, Serhiy Storchaka wrote: > 04.07.18 04:26, Tim Peters пише: >> >> I really don't know what Guido likes best about this, but for me it's the >> large number of objectively small wins in `if` and `while` contexts. They >> add up. That conclusion surprised me. That there are occasionally bigger >> wins to be had is pure gravy. > > > Could you please show me several examples in real code? I have not seen any > win yet. The new version of the PEP has several real examples -- there are some "sanitized" ones in this section inspired by Guido's trawling through Dropbox code: https://www.python.org/dev/peps/pep-0572/#the-importance-of-real-code And Tim's appendix has several more, most from his code plus one that Kirill Balunov found in the stdlib: https://www.python.org/dev/peps/pep-0572/#appendix-a-tim-peters-s-findings This is much nicer than the old PEP! Unfortunately I don't find any of these examples convincing myself :-(. Most of them (the Dropbox ones and the first few in Tim's appendix) look like great arguments for pattern matching syntax, which is basically an elegant way of writing chained 'if's and capturing values along the way. And at PyCon Guido was saying he hoped we'd also get a good proposal for pattern matching syntax for 3.8, so for these cases := will hopefully be obsolete before it even ships... The last two in Tim's appendix are the "best" examples, in the sense that they really do depend on the full power of :=. Unfortunately (as Tim acknowledges) the code is fairly incomprehensible to non-Tims regardless of which syntax is used, so to me they aren't really any more convincing than foo/bar examples. But, if I found myself forced to maintain this code, my first step in deciphering it would be to rewrite it to remove the :='s, just to simplify the control flow, so that I could focus on understanding each statement in isolation. The PEP spends a ton of time talking about comprehensions, but still has zero real examples of comprehensions that would be improved by :=. The only cases that seem potentially valuable to me are the ones that are literally the form 'if := ` and 'while := '. (I suspect these are the only cases that I would allow in code that I maintain.) The PEP does briefly discuss the alternative proposal of restricting to just these two cases, but rejects it because it would rule out code like 'if ( := ) '. But those are exactly the cases that I want to rule out, so that seems like a plus to me :-). The 'if as ' syntax would be a simple way to encode exactly these simple non-harmful cases. The PEP rejects it on the grounds that 'as' is already used in a different way by 'except' and 'with'. But... 'as' is *also* used in the *same* way by 'import', so the argument feels disengenuous. Yeah, there'd be an inconsistency, but that inconsistency already exists, and adding 'if ... as' and 'while ... as' wouldn't create any *new* inconsistencies. Guido has asked for PRs to the PEP to flesh out the rejected alternatives and replies-to-common-complaints sections, and I'd be happy to write up something for that, except that despite all the electrons that have been spilled I actually do not know what the PEP authors response would be to the issues that bother me :-(. -n -- Nathaniel J. Smith -- https://vorpus.org ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, Jul 3, 2018 at 11:07 PM, Serhiy Storchaka wrote: > 04.07.18 00:51, Chris Angelico пише: >> >> On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka >> wrote: >>> >>> I believe most Python users are not >>> professional programmers -- they are sysadmins, scientists, hobbyists and >>> kids -- >> >> >> [citation needed] > > > I don't understand what citation do you need. > >>> In particularly mutating and >>> non-mutating operations are separated. The assignment expression breaks >>> this. >> >> >> [citation needed] > > > In Python the assignment (including the augmented assignment) is a > statement, del is a statement, function and class declarations are > statements, import is a statement. Mutating methods like list.sort() and > dict.update() return None to discourage using them in expressions. This a > common knowledge, I don't know who's citation you need. Right, Python has a *very strong* convention that each line should have at most one side-effect, and that if it does have a side-effect it should be at the outermost level. I think the most striking evidence for this is that during the discussion of PEP 572 we discovered that literally none of us – including Guido – even *know* what the order-of-evaluation is inside expressions. In fact PEP 572 now has a whole section talking about the oddities that have turned up here so far, and how to fix them. Which just goes to show that even its proponents don't actually think that anyone uses side-effects inside expressions, because if they did, then they'd consider these changes to be compatibility-breaking changes. Of course the whole point of PEP 572 is to encourage people to embed side-effects inside expressions, so I hope they've caught all the weird cases, because even if we can still change them now we won't be able to after PEP 572 is implemented. Some people make fun of Python's expression/statement dichotomy, because hey don't you know that everything can be an expression, functional languages are awesome hurhur, but I think Python's approach is actually very elegant. Python is unapologetically an imperative language, but even we dirty imperative programmers can agree with the functional fanatics that reasoning about side-effects and sequencing is hard. One-side-effect-per-line is a very elegant way to keep sequencing visible on the page and as easy to reason about as possible. Or as Dijkstra put it: "our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do (as wise programmers aware of our limitations) our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible." It's very disheartening that not only is PEP 572 apparently going to be accepted, but as far as I can tell neither the text nor its proponents have even addressed this basic issue. -n -- Nathaniel J. Smith -- https://vorpus.org ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
[Tim] >> I really don't know what Guido likes best about this, but for me it's > >> the large number of objectively small wins in `if` and `while` > >> contexts. They add up. That conclusion surprised me. That there are > >> occasionally bigger wins to be had is pure gravy. > [Serhiy Storchaka] > Could you please show me several examples in real code? I > have not seen any win yet. My PEP Appendix was derived entirely from looking at real code. If you don't believe the examples I showed there are wins (and I don't know whether you've seen them, because your original message in this thread only echoed examples from the body of the PEP), then what we each mean by "win" in this context has no intersection, so discussing it would be futile (for both of us). Which is what I expect: the treatment you gave to the examples from the body of the PEP suggests you're determined not to acknowledge any "win", however small. Which is fine by me, but if so it's an extreme position. I don't recall anyone else over the months this has been active who claimed the PEP is 100% loss (not in its current form, or in any of its earlier forms). Even those who hate it passionately have argued instead that downsides outweigh benefits - not that there are no benefits whatsoever. So making such a claim: > It looks to me that there is no use case for PEP 572. It just makes > Python worse. comes across more as trolling than sincere inquiry. It's possible you really can't imagine how anyone could see any benefits here. But then, as above,, our worldviews probably differ too much for communication to be possible - there must be going on a thousand messages in these threads by now, and across all these months you still have no idea why anyone would want this? If so, you're more an unmovable object than I am an irresistible force ;-) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 4:07 PM, Serhiy Storchaka wrote: > 04.07.18 00:51, Chris Angelico пише: >> >> On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka >> wrote: >>> >>> I believe most Python users are not >>> professional programmers -- they are sysadmins, scientists, hobbyists and >>> kids -- >> >> >> [citation needed] > > > I don't understand what citation do you need. Anything at all that suggests that "most Python users are not professional programmers". Anything beyond just a hunch of yours. >>> In particularly mutating and >>> non-mutating operations are separated. The assignment expression breaks >>> this. >> >> >> [citation needed] > > > In Python the assignment (including the augmented assignment) is a > statement, del is a statement, function and class declarations are > statements, import is a statement. Mutating methods like list.sort() and > dict.update() return None to discourage using them in expressions. This a > common knowledge, I don't know who's citation you need. "Assignment is a statement" -- that's exactly the point under discussion. "del is a statement" -- yes, granted "function and class declarations are statements" -- class, yes, but you have "def" and "lambda" as statement and expression equivalents. "import is a statement" -- but importlib.import_module exists for a reason So you have two statements (del and class), one statement with a function form (import), and one statement with an expression form (def/lambda). I'm going to assume that your term "mutating" there was simply a miswording, and that you're actually talking about *name binding*, which hitherto occurs only in statements. Yes, this is true. And it's the exact point under discussion - that restricting name bindings to statements is unnecessary. ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
04.07.18 04:26, Tim Peters пише: I really don't know what Guido likes best about this, but for me it's the large number of objectively small wins in `if` and `while` contexts. They add up. That conclusion surprised me. That there are occasionally bigger wins to be had is pure gravy. Could you please show me several examples in real code? I have not seen any win yet. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
04.07.18 03:24, INADA Naoki пише: I feel PEP 572 breaks border between expression and statement, and it makes readability of dirty code worse. Thank you, this is what I meant. On the other hand, I understand PEP 572 allows clever code simplifies tedious code. It may increase readability of non-dirty code. Unfortunately, I have not seen any example of this yet. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
04.07.18 00:51, Chris Angelico пише: On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka wrote: I believe most Python users are not professional programmers -- they are sysadmins, scientists, hobbyists and kids -- [citation needed] I don't understand what citation do you need. In particularly mutating and non-mutating operations are separated. The assignment expression breaks this. [citation needed] In Python the assignment (including the augmented assignment) is a statement, del is a statement, function and class declarations are statements, import is a statement. Mutating methods like list.sort() and dict.update() return None to discourage using them in expressions. This a common knowledge, I don't know who's citation you need. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, Jul 03, 2018 at 09:54:22PM -0400, Terry Reedy wrote: > > results = [(x, y, x/y) for x in input_data for y in [f(x)] if y > 0] > > Would (f(x),) be faster? There is a deferred feature request to optimize "for x in [item]" as equivalent to "for x in (item,)", to avoid constructing a list: https://bugs.python.org/issue32856 Since it only affects the internal byte-code, not visible semantics (aside from speed and memory) I think that's a neat micro-optimization regardless of whether it is applied to comprehensions or regular for-loops or both. -- Steve ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On 7/3/2018 5:37 PM, Serhiy Storchaka wrote: I like programming languages in which all are expressions (including function declarations, branching and loops) and you can use an assignment at any point, but Python is built on other ways, and I like Python too. PEP 572 looks violating several Python design principles. Python looks simple language, and this is its strong side. I believe most Python users are not professional programmers -- they are sysadmins, scientists, hobbyists and kids -- but Python is suitable for them because its clear syntax and encouraging good style of programming. In particularly mutating and non-mutating operations are separated. The assignment expression breaks this. There should be very good reasons for doing this. But it looks to me that all examples for PEP 572 can be written better without using the walrus operator. I appreciate you showing alternatives I can use now. Even once implemented, one can not use A.E's until one no longer cares about 3.7 compatibility. Then there will still be a choice. results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0] results = [(x, y, x/y) for x in input_data for y in [f(x)] if y > 0] Would (f(x),) be faster? import timeit as ti print(ti.timeit('for y in {x}: pass', 'x=1')) print(ti.timeit('for y in [x]: pass', 'x=1')) print(ti.timeit('for y in (x,): pass', 'x=1')) # prints 0.1376525449996 # seconds per 1_000_000 = microseconds each. 0.103212743 0.0949247330004 Yes, but not enough to pay for adding ',', and sometimes forgetting. stuff = [[y := f(x), x/y] for x in range(5)] stuff = [[y, x/y] for x in range(5) for y in [f(x)]] Creating an leaky name binding appears to about 5 x faster than iterating a temporary singleton. print(ti.timeit('y=x', 'x=1')) print(ti.timeit('y=x; del y', 'x=1')) # 0.01735777899907 0.02111505100107 If one adds 'del y' to make the two equivalent, the chars typed is about the same. To me, the choice amounts to subject reference. Even with y:=x available, I would write the expansion as res = [] for x in range(5): y = f(x) res.append((y, x/y)) rather than use the assignment expression in the tuple. It creates a 'hitch' in thought. This idiom looks unusual for you? But this is a legal Python syntax, and it is not more unusual than the new walrus operator. This idiom is not commonly used because there is very little need of using above examples in real code. And I'm sure that the walrus operator in comprehension will be very rare unless PEP 572 will encourage writing complicated comprehensions. Most users prefer to write an explicit loop. I want to remember that PEP 572 started from the discussion on Python-ideas which proposed a syntax for writing the following code as a comprehension: smooth_signal = [] average = initial_value for xt in signal: average = (1-decay)*average + decay*xt smooth_signal.append(average) Using the "for in []" idiom this can be written (if you prefer comprehensions) as: smooth_signal = [average for average in [initial_value] for x in signal for average in [(1-decay)*average + decay*x]] Try now to write this using PEP 572. The walrus operator turned to be less suitable for solving the original problem because it doesn't help to initialize the initial value. Examples from PEP 572: # Loop-and-a-half while (command := input("> ")) != "quit": print("You entered:", command) The straightforward way: while True: command = input("> ") if command == "quit": break print("You entered:", command) The clever way: for command in iter(lambda: input("> "), "quit"): print("You entered:", command) The 2-argument form of iter is under-remembered and under-used. The length difference is 8. while (command := input("> ")) != "quit": for command in iter(lambda: input("> "), "quit"): I like the iter version, but the for-loop machinery and extra function call makes a minimal loop half a millisecond slower. import timeit as ti def s(): it = iter(1*'0' + '1') def w(): it = iter(1*'0' + '1') while True: command = next(it) if command == '1': break def f(): it = iter(1*'0' + '1') for command in iter(lambda: next(it), '1'): pass print(ti.timeit('s()', 'from __main__ import s', number=1000)) print(ti.timeit('w()', 'from __main__ import w', number=1000)) print(ti.timeit('f()', 'from __main__ import f', number=1000)) # 0.00097021275 0.936525425001 1.591311794998 Of course, with added processing of 'command' the time difference disappears. Printing (in IDLE) is an extreme case. def wp(): it = iter(100*'0' + '1') while True: command = next(it) if command == '1': break print('w', command) def fp(): it = iter(100*'0' + '1') for command in
Re: [Python-Dev] Examples for PEP 572
[INADA Naoki] > ... > On the other hand, I understand PEP 572 allows clever code > simplifies tedious code. It may increase readability of non-dirty code. The latter is the entire intent ,of course. We can't force people to write readable code, but I don't understand the widespread assumption that other programmers are our enemies who have to be preemptively disarmed ;-) Use code review to enforce readable code. If you want a coding standard here, use mine: "if using an assignment expression isn't obviously better (at least a little so), DON'T USE IT". That's the same standard I use for lots of things (e.g., is such-&-such better as a listcomp or as nested loops?). It only requires that you have excellent taste in what "better" means ;-) As I noted in the PEP's Appendix A, I refuse to even write code like i = j = count = nerrors = 0 because it squashes conceptually distinct things into a single statement . I'll always write that as i = j = 0 count = 0 nerrors = 0 instead - or even in 4 lines if `i` and `j` aren't conceptually related. That's how annoyingly pedantic I can be ;-) Yet after staring at lots of code, starting from a neutral position (why have an opinion about anything before examination?), I became a True Believer. I really don't know what Guido likes best about this, but for me it's the large number of objectively small wins in `if` and `while` contexts. They add up. That conclusion surprised me. That there are occasionally bigger wins to be had is pure gravy. But in no case did I count "allows greater cleverness" as a win. The Appendix contains a few examples of "bad" uses too, where cleverness in pursuit of brevity harms clarity. In fact, to this day, I believe those examples derived from abusing assignment expressions in real-life code are more horrifying than any of the examples anyone else _contrived_ to "prove" how bad the feature is. I apparently have more faith that people will use the feature as intended. Not all people, just most. The ones who don't can be beaten into compliance, same as with any other abused feature ;-) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
> > In particularly mutating and > > non-mutating operations are separated. The assignment expression breaks > > this. > > [citation needed] > > In terms of blending mutating and non-mutating operations, augmented > assignment is far worse. Contrast: > > >>> x = 1 > >>> y = x > >>> x += 1 > > >>> a = [1] > >>> b = a > >>> a += [2] > > > Assignment expressions do the exact same thing as assignment > statements, but also allow you to keep using that value. There is > nothing about mutation. (Unless you believe that assignment *itself* > is mutation, in which case Python is definitely the wrong language for > you.) > > I think Serhiy use "mutation" as "assignment", or "changing variable". And at this point, I'm with Serhiy. Before PEP 572, assignment is happened on very limited places. When we want to use "variable x", we can check "x isn't changed from value I want" very quickly, without reading full code. For example, with open(some_file) as f: for line in f: line = line.rstrip() # some code here self.some_method(..., # some long arguments (line := line.split())[0], line[1], # oops! ...) # some code here x = {k: f for k in line if (f := k.upper()).startswith('F')} # oops! # some code here Before PEP 572, we can check "f is not changed from `as f`" and "line is not changed from `line = line.rstrip()`" very quickly, without reading expressions in argument list or comprehension. After PEP 572, we need to read all code between place we want to use some variable and these variables are assigned to expected value. In this meaning, augmented assignment is far better than assignment expression. It's very easy to find, same to "as x" or "x =". So PEP 572 will reduce maintainability of code written by others (1) (1) "others" including "I" in several months ago. Linters helps us sometime, but linter can't help us when others who written the code didn't use linter and it's difficult to solve every warning from linters. This is what I feel how PEP 572 is different from f-string or ternary expression. f-string and ternary expression can do only what expressions can. But PEP 572 expands "what expressions can". I feel PEP 572 breaks border between expression and statement, and it makes readability of dirty code worse. On the other hand, I understand PEP 572 allows clever code simplifies tedious code. It may increase readability of non-dirty code. Regards, -- INADA Naoki ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Tue, Jul 3, 2018 at 2:51 PM, Chris Angelico wrote: > On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka > wrote: > > I believe most Python users are not > > professional programmers -- they are sysadmins, scientists, hobbyists and > > kids -- > > [citation needed] fair enough, but I think we all agree that *many*, if not most, Python users are "not professional programmers". While on the other hand everyone involved in discussion on python-dev and python-ideas is a serious (If not "professional") programmer. So we do have a bit of a disconnect between much of the user base and folks making decisions about how the language evolves -- which is probably inevitable, Over the years I've been using it (most of its life), Python has evolved to become much less of a "scripting" language, and much more of a "systems" language, and this addition is a (pretty significant) step more in that direction. Serhiy: FWIW, a number of us made the case about the additional complexity of this feature in this discussion -- I think it was a bit side-tracked by the impression that we were only talking about newbies (and also by scope of comprehensions), but the point was made and I assume considered. > > In particularly mutating and > > non-mutating operations are separated. The assignment expression breaks > > this. > I'd call it "local namespace manipulating and non-local namespace manipulating", but yes, that is my concern as well. In terms of blending mutating and non-mutating operations, augmented > assignment is far worse. yeah -- I've always thought it was a shame that augmented assignment worked on immutables :-( -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R(206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception chris.bar...@noaa.gov ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Examples for PEP 572
On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka wrote: > I believe most Python users are not > professional programmers -- they are sysadmins, scientists, hobbyists and > kids -- [citation needed] > In particularly mutating and > non-mutating operations are separated. The assignment expression breaks > this. [citation needed] In terms of blending mutating and non-mutating operations, augmented assignment is far worse. Contrast: >>> x = 1 >>> y = x >>> x += 1 >>> a = [1] >>> b = a >>> a += [2] Assignment expressions do the exact same thing as assignment statements, but also allow you to keep using that value. There is nothing about mutation. (Unless you believe that assignment *itself* is mutation, in which case Python is definitely the wrong language for you.) ChrisA ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Examples for PEP 572
I like programming languages in which all are expressions (including function declarations, branching and loops) and you can use an assignment at any point, but Python is built on other ways, and I like Python too. PEP 572 looks violating several Python design principles. Python looks simple language, and this is its strong side. I believe most Python users are not professional programmers -- they are sysadmins, scientists, hobbyists and kids -- but Python is suitable for them because its clear syntax and encouraging good style of programming. In particularly mutating and non-mutating operations are separated. The assignment expression breaks this. There should be very good reasons for doing this. But it looks to me that all examples for PEP 572 can be written better without using the walrus operator. results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0] results = [(x, y, x/y) for x in input_data for y in [f(x)] if y > 0] stuff = [[y := f(x), x/y] for x in range(5)] stuff = [[y, x/y] for x in range(5) for y in [f(x)]] This idiom looks unusual for you? But this is a legal Python syntax, and it is not more unusual than the new walrus operator. This idiom is not commonly used because there is very little need of using above examples in real code. And I'm sure that the walrus operator in comprehension will be very rare unless PEP 572 will encourage writing complicated comprehensions. Most users prefer to write an explicit loop. I want to remember that PEP 572 started from the discussion on Python-ideas which proposed a syntax for writing the following code as a comprehension: smooth_signal = [] average = initial_value for xt in signal: average = (1-decay)*average + decay*xt smooth_signal.append(average) Using the "for in []" idiom this can be written (if you prefer comprehensions) as: smooth_signal = [average for average in [initial_value] for x in signal for average in [(1-decay)*average + decay*x]] Try now to write this using PEP 572. The walrus operator turned to be less suitable for solving the original problem because it doesn't help to initialize the initial value. Examples from PEP 572: # Loop-and-a-half while (command := input("> ")) != "quit": print("You entered:", command) The straightforward way: while True: command = input("> ") if command == "quit": break print("You entered:", command) The clever way: for command in iter(lambda: input("> "), "quit"): print("You entered:", command) # Capturing regular expression match objects # See, for instance, Lib/pydoc.py, which uses a multiline spelling # of this effect if match := re.search(pat, text): print("Found:", match.group(0)) # The same syntax chains nicely into 'elif' statements, unlike the # equivalent using assignment statements. elif match := re.search(otherpat, text): print("Alternate found:", match.group(0)) elif match := re.search(third, text): print("Fallback found:", match.group(0)) It may be more efficient to use a single regular expression which consists of multiple or-ed patterns marked as different groups. For example see the cute regex-based tokenizer in gettext.py: _token_pattern = re.compile(r""" (?P[ \t]+)| # spaces and horizontal tabs (?P[0-9]+\b) | # decimal integer (?Pn\b) | # only n is allowed (?P[()]) | (?P[-*/%+?:]|[>, # <=, >=, ==, !=, &&, ||, # ? : # unary and bitwise ops # not allowed (?P\w+|.) # invalid token """, re.VERBOSE|re.DOTALL) def _tokenize(plural): for mo in re.finditer(_token_pattern, plural): kind = mo.lastgroup if kind == 'WHITESPACES': continue value = mo.group(kind) if kind == 'INVALID': raise ValueError('invalid token in plural form: %s' % value) yield value yield '' I have not found any code similar to the PEP 572 example in pydoc.py. It has different code: pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|' r'RFC[- ]?(\d+)|' r'PEP[- ]?(\d+)|' r'(self\.)?(\w+))') ... start, end = match.span() results.append(escape(text[here:start])) all, scheme, rfc, pep, selfdot, name = match.groups() if scheme: url = escape(all).replace('"', '"') results.append('%s' % (url, url)) elif rfc: url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc) results.append('%s' % (url, escape(all))) elif pep: ... It doesn't look as a sequence of re.search() calls. It is