Re: [Python-Dev] Examples for PEP 572

2018-07-06 Thread Brett Cannon
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

2018-07-06 Thread Mike Miller



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

2018-07-05 Thread Devin Jeanpierre
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

2018-07-05 Thread Chris Barker via Python-Dev
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

2018-07-04 Thread Terry Reedy

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

2018-07-04 Thread Terry Reedy

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

2018-07-04 Thread Terry Reedy

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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Ivan Pozdeev via Python-Dev

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

2018-07-04 Thread Sven R. Kunze

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

2018-07-04 Thread Devin Jeanpierre
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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Terry Reedy

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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Nathaniel Smith
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

2018-07-04 Thread Sven R. Kunze

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

2018-07-04 Thread Stéfane Fermigier
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

2018-07-04 Thread Yury Selivanov
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

2018-07-04 Thread Stéfane Fermigier
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

2018-07-04 Thread Rob Cliffe via Python-Dev



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

2018-07-04 Thread Kirill Balunov
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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Tim Peters
[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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Tim Peters
[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

2018-07-04 Thread Yury Selivanov
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

2018-07-04 Thread Ivan Pozdeev via Python-Dev

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

2018-07-04 Thread Devin Jeanpierre
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

2018-07-04 Thread David Mertz
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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Antoine Pitrou
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

2018-07-04 Thread David Mertz
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

2018-07-04 Thread Chris Angelico
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

2018-07-04 Thread David Mertz
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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Steven D'Aprano
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

2018-07-04 Thread Brett Cannon
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

2018-07-04 Thread Chris Angelico
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 Thread Victor Stinner
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

2018-07-04 Thread Serhiy Storchaka

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

2018-07-04 Thread Antoine Pitrou
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

2018-07-04 Thread Devin Jeanpierre
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

2018-07-04 Thread Serhiy Storchaka

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

2018-07-04 Thread Serhiy Storchaka

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

2018-07-04 Thread Nathaniel Smith
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

2018-07-04 Thread Nathaniel Smith
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

2018-07-04 Thread 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).

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

2018-07-04 Thread Chris Angelico
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

2018-07-03 Thread Serhiy Storchaka

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

2018-07-03 Thread Serhiy Storchaka

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

2018-07-03 Thread Serhiy Storchaka

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

2018-07-03 Thread 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

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

2018-07-03 Thread Terry Reedy

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

2018-07-03 Thread Tim Peters
[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

2018-07-03 Thread INADA Naoki
​

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

2018-07-03 Thread Chris Barker via Python-Dev
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

2018-07-03 Thread 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]

> 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

2018-07-03 Thread Serhiy Storchaka
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