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] PEP 572 semantics: all capabilities of the assignment statement

2018-07-04 Thread Chris Angelico
On Thu, Jul 5, 2018 at 3:15 PM, Guido van Rossum  wrote:
> Let me be slightly contrarian. :-)
>
> On Wed, Jul 4, 2018 at 9:12 PM Chris Angelico  wrote:
>> 2) Is the result of the expression the modified value or the original?
>
> Someone (sadly I forget who) showed, convincingly (to me anyways :-) that it
> should return whatever the `__iadd__` method returns, or (if there isn't
> one) the result of `a = a + b`.

I happen to feel the same way, but it does destroy the elegance of "x
:= expr" having the exact same value as "expr", and ALSO having the
exact same value as "x". But yes, the biggest argument is the lack of
use cases, for both iadd and unpacking.

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] PEP 572 semantics: all capabilities of the assignment statement

2018-07-04 Thread Guido van Rossum
Let me be slightly contrarian. :-)

On Wed, Jul 4, 2018 at 9:12 PM Chris Angelico  wrote:

> Definitely against augmentation, for several reasons:
>
> 1) Spelling - should it be :+= or +:= ?
>

That one's easy. As Nick's (withdrawn) PEP 577 shows it should be simply
`+=`.


> 2) Is the result of the expression the modified value or the original?
>

Someone (sadly I forget who) showed, convincingly (to me anyways :-) that
it should return whatever the `__iadd__` method returns, or (if there isn't
one) the result of `a = a + b`.


> 3) The use-cases simply aren't as strong.
>

Here I agree.


> Supporting arbitrary assignment targets (rather than just a simple
> name) could be useful, but can be deferred to a future enhancement
> without impacting the simpler version. I would divide this up into two
> subgroups:
>
> * Multiple assignment (sequence unpacking)
>

Tim Peters showed in his response this isn't all that helpful. I also think
we shouldn't open the can of worms about priorities this presents, e.g. is
(a, b := foo()) equivalent to ((a, b) := foo()) or is it like (a, (b :=
foo()))?


> * Assignment to non-simple names eg "x[1] := expr"
>
> Assigning directly to an item or attribute could in theory be
> immensely valuable. So could multiple assignment, though I suspect to
> a lesser extent. But tell me: Without looking it up, do you know which
> of these constructs support non-simple-name assignment and which
> don't?
>
> [x[1] for x[1] in seq]
> with ctx() as x[1]:
> except Exception as x[1]:
> from spam import ham as x[1]
>
> In the enormous majority of cases, every one of these constructs is
> going to be used with a simple name, even though some (I won't say how
> many) do permit you to do what I did here. If Python 3.8 ships with
> assignment expressions restricted to simple names, we can discuss how
> valuable the other forms of assignment target would be, and then
> figure out what to do about the ambiguities - for instance, is "x, y
> := expr" going to be equivalent to "x, (y := expr)" or "(x, y) :=
> expr" ? As it is, we neatly dodge that.
>

Again, the biggest argument against this is that there just aren't enough
use cases.

-- 
--Guido van Rossum (python.org/~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 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] PEP 484

2018-07-04 Thread Greg Ewing

Shawn Chen wrote:
The PEP 484 is proposing a type hint which can annotate the type of each 
parameters. How ever code written in this format can not be run for 
python3.5 and below.


You're a bit late. Parameter annotations have been a part
of the language since at least 3.1. PEP 484 just codifies
a way of using them to represent types.

Also, PEP 484 does specify a way of using comments to
indicate types.

--
Greg
___
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] PEP 484

2018-07-04 Thread Ryan Gonzalez
Type hints like in PEP 484 work on all Python 3 versions, and something 
similar to your proposal is already supported on Python 2 [1].


[1]: https://mypy.readthedocs.io/en/latest/python2.html


On July 4, 2018 11:08:27 PM Shawn Chen  wrote:


Hello,

Here, I am proposing a change on python type annotation.

Python was born to be a simple and elegant language. However recent change 
has again introduce new incompatibility to python.


The PEP 484 is proposing a type hint which can annotate the type of each 
parameters. How ever code written in this format can not be run for 
python3.5 and below.


It is an exciting new feature to be able to know the data type from the 
code, But I am afraid this is not worth such a incompatibility.


Here I want to propose a new way of annotation in python as follows

def reportAge(name, age):
''' this a a greeting function and some other comment...
!str, int -> str
'''
return name+' is ' + age


we can put the annotation in the comment block and use a symbol '!' or 
other symbol suitable to lead a annotation line.

the annotation should be positionally corresponding to the parameters.

Shawn

Sent from Mail for Windows 10




--
___
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/rymg19%40gmail.com


___
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] PEP 572 semantics: all capabilities of the assignment statement

2018-07-04 Thread Chris Angelico
On Thu, Jul 5, 2018 at 1:28 PM, Ivan Pozdeev via Python-Dev
 wrote:
> Victor Stinner in "Assignment expression and coding style: the while True
> case" and others have brought to attention
>
> that the AE as currently written doesn't support all the capabilities of the
> assignment statement, namely:
>
> * tuple unpacking
> * augmented assignment
>
> (I titled the letter "all capabilities" 'cuz I may've missed something.)
>
> Should it?
>
> Personally, I'm for the unpacking but against augmentation 'cuz it has
> proven incomprehensible as per the 5 Jul 2018 04:22:36 +0300 letter.
>

Definitely against augmentation, for several reasons:

1) Spelling - should it be :+= or +:= ?
2) Is the result of the expression the modified value or the original?
3) The use-cases simply aren't as strong.

Supporting arbitrary assignment targets (rather than just a simple
name) could be useful, but can be deferred to a future enhancement
without impacting the simpler version. I would divide this up into two
subgroups:

* Multiple assignment (sequence unpacking)
* Assignment to non-simple names eg "x[1] := expr"

Assigning directly to an item or attribute could in theory be
immensely valuable. So could multiple assignment, though I suspect to
a lesser extent. But tell me: Without looking it up, do you know which
of these constructs support non-simple-name assignment and which
don't?

[x[1] for x[1] in seq]
with ctx() as x[1]:
except Exception as x[1]:
from spam import ham as x[1]

In the enormous majority of cases, every one of these constructs is
going to be used with a simple name, even though some (I won't say how
many) do permit you to do what I did here. If Python 3.8 ships with
assignment expressions restricted to simple names, we can discuss how
valuable the other forms of assignment target would be, and then
figure out what to do about the ambiguities - for instance, is "x, y
:= expr" going to be equivalent to "x, (y := expr)" or "(x, y) :=
expr" ? As it is, we neatly dodge that.

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] PEP 484

2018-07-04 Thread Shawn Chen

Hello,

Here, I am proposing a change on python type annotation.

Python was born to be a simple and elegant language. However recent change has 
again introduce new incompatibility to python.

The PEP 484 is proposing a type hint which can annotate the type of each 
parameters. How ever code written in this format can not be run for python3.5 
and below.

It is an exciting new feature to be able to know the data type from the code, 
But I am afraid this is not worth such a incompatibility.

Here I want to propose a new way of annotation in python as follows

def reportAge(name, age):
''' this a a greeting function and some other comment...
!str, int -> str
'''
return name+' is ' + age


we can put the annotation in the comment block and use a symbol '!' or other 
symbol suitable to lead a annotation line.
the annotation should be positionally corresponding to the parameters.

Shawn

Sent from Mail for Windows 10

___
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] PEP 572 semantics: all capabilities of the assignment statement

2018-07-04 Thread Tim Peters
[Ivan Pozdeev]

> Victor Stinner in "Assignment expression and coding style: the while
> True case" and others have brought to attention
>
> that the AE as currently written doesn't support all the capabilities of
> the assignment statement, namely:
>
> * tuple unpacking
> * augmented assignment
>
> (I titled the letter "all capabilities" 'cuz I may've missed something.)
>
> Assignment statements (and `for` headers) also allow arbitrarily complex
applications of subscripting and attribute references.  Like

for a[b].cde[f, g(h, i, j)].k in range(10):



> Should it?
>

Already been considered and rejected, so no.

Victor already showed why, but didn't quite realize it ;-)

while True:
name, token = _getname(g)
if not name:
break

Allowing to unpack the two names in an AE wouldn't really help, because
there's still no satisfying way then to _reference_ just the `name` part in
the `while` test:

while ((name, token) := _getname(g)) ... and now what??

You could use "a trick", relying on that a 2-tuple is always truthy:

while ((name, token) := _getname(g)) and name:

Using a trick sucks.  Not relying on a trick is ugly and inefficient:

while [((name, token) := _getname(g)), name][-1]:
or
while [((name, token) := _getname(g)), name].pop():

where the thing to be tested is the second list element (e.g., `name ==
"not done yet"`).

So no plausible use cases were ever presented, and the idea was dropped.

If we _also_ added something akin to C's comma expressions (evaluate a
sequence of expressions and throw away all the results except for the
last), then a reasonable spelling akin to the last one above could be used,
but without the strained cruft to muck with a result list (or tuple).

At which point my rule for AE would likely never trigger ("if it's not
obviously better, don't use it").
___
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] Comparing PEP 576 and PEP 580

2018-07-04 Thread INADA Naoki
On Thu, Jul 5, 2018 at 1:13 AM Jeroen Demeyer  wrote:
>
> On 2018-07-04 03:31, INADA Naoki wrote:
> > I think both PEPs are relying on FASTCALL calling convention,
> > and can't be accepted until FASTCALL is stable & public.
>
> First of all, the fact that FASTCALL has not been made public should
> not prevent from discussing those PEPs and even making a
> (provisional?) decision on them. I don't think that the precise
> API of FASTCALL really matters that much.
>
> More importantly, I don't think that you can separate making FASTCALL
> public from PEP 576/580. As you noted in [1], making FASTCALL public
> means more than just documenting METH_FASTCALL.
>
> In particular, a new API should be added for calling objects using the
> FASTCALL convention.

I meant _PyArg_ParseStack should be public when METH_FASTCALL is public.
Without argument parsing API, it's not practical to implement methods
with METH_FASTCALL.

I didn't mean other APIs for calling (e.g. _PyObject_FastCall, etc).
Without these APIs, 3rd parties can use METH_FASTCALL for tp_methods
and m_methods, like stdlibs.
Existing public APIs like PyObject_CallMethod() use FASTCALL internally too.

So we **can** make public METH_FASTCALL, before make calling APIs public.

And stabilizing calling convention is prerequirements of designing new
calling APIs.
That's why I suggest discussing METH_FASTCALL first.

>
> Here I mean both an abstract API for arbitrary
> callables as well as a specific API for certain classes. Since PEP 580
> (and possibly also PEP 576) proposes changes to the implementation of
> FASTCALL, it makes sense to design the public API for FASTCALL after
> it is clear which of those PEPs (if any) is accepted. If we fix the
> FASTCALL API now, it might not be optimal when either PEP 576 or PEP 580
> is accepted.
>

I agree that calling APIs should be discusses with PEP 580.

But I didn't mean FASTCALL calling API, but low level FASTCALL calling
convention
used for tp_methods and m_methods and parsing APIs for it.
Does both PEPs suggests changing it?  I didn't think so.

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


[Python-Dev] PEP 572 semantics: all capabilities of the assignment statement

2018-07-04 Thread Ivan Pozdeev via Python-Dev
Victor Stinner in "Assignment expression and coding style: the while 
True case" and others have brought to attention


that the AE as currently written doesn't support all the capabilities of 
the assignment statement, namely:


* tuple unpacking
* augmented assignment

(I titled the letter "all capabilities" 'cuz I may've missed something.)

Should it?

Personally, I'm for the unpacking but against augmentation 'cuz it has 
proven incomprehensible as per the 5 Jul 2018 04:22:36 +0300 letter.


--
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 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] PEP 572, VF/B, and "Shark Jumping"

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

On 05.07.2018 2:52, Mike Miller wrote:

Recently on Python-Dev:

On 2018-07-03 15:24, Chris Barker wrote:
> On Tue, Jul 3, 2018 at 2:51 PM, Chris Angelico > On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka 


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


Python Audience - wants clarity:

Not sure I'd say that most users are not professionals, but one major 
strength of Python is its suitability as a teaching language, which 
enlarges the community every year.


Additionally, I have noticed a dichotomy between prolific "C 
programmers" who've supported this PEP and many Python programmers who 
don't want it.  While C-devs use this construct all the time, their 
stereotypical Python counterpart is often looking for simplicity and 
clarity instead.  That's why we're here, folks.



Value - good:

Several use cases are handled well by PEP 572.  However it has been 
noted that complexity must be capped voluntarily relatively early—or 
the cure soon becomes worse than the disease.



Frequency - not much:

The use cases for assignment-expressions are not exceedingly common, 
coming up here and there.  Their omission has been a very mild burden 
and we've done without for a quarter century.


Believe the authors agreed that it won't be used too often and won't 
typically be mis- or overused.



New Syntax - a high burden:

For years I've read on these lists that syntax changes must clear a 
high threshold of the (Value*Frequency)/Burden (or VF/B) ratio.


Likewise, a few folks have compared PEP 572 to 498 (f-strings) which 
some former detractors have come to appreciate.  Don't believe this 
comparison applies well, since string interpolation is useful a 
hundred times a day, more concise, clear, and runs faster than 
previous functionality.  Threshold was easily cleared there.



Conclusion:

An incongruous/partially redundant new syntax to perform existing 
functionality more concisely feels too low on the VF/B ratio IMHO.  
Value is good though mixed, frequency is low, and burden is higher 
than we'd like, resulting in "meh" and binary reactions.


Indeed many modern languages omit this feature specifically in an 
effort to reduce complexity, ironically citing the success of Python 
in support.  Less is more.



Compromise:

Fortunately there is a compromise design that is chosen often these 
days in new languages---restricting these assignments to if/while 
(potentially comp/gen) statements.


https://mail.python.org/pipermail/python-dev/2018-July/154343.html :
"Any construct that accepts an expression and uses its result but 
doesn't allow to insert an additional line in the middle qualifies."


If/when is not enough.

And https://mail.python.org/pipermail/python-dev/2018-June/154160.html 
disproves the "chosen often these days in new languages".


We can also reuse the existing "EXPR as NAME" syntax that already 
exists and is widely enjoyed.




For the record, with "as", Victor Stinner's examples from the 5 Jul 2018 
00:51:37 +0200 letter would look like:


while expr as x:

while input.readline() as line:

while (c//n as q) < n:

while (self.__read(1) as s) and s != NUL:

while (self.next() as tarinfo) is not None:
pass

while (match() as m) and (m.end() as j) == i:



This compromise design:

    1  Handles the most common cases (of a group of infrequent cases)
    0  Doesn't handle more obscure cases.
    1  No new syntax (through reuse)
    1  Looks Pythonic as hell
    1  Difficult to misuse, complexity capped

    Score: 4/5

PEP 572:

    1  Handles the most common cases (of a group of infrequent cases)
    1  Handles even more obscure cases.
    0  New syntax
    0  Denser look: more colons, parens, expression last
    0  Some potential for misuse, complexity uncapped

    Score: 2/5


Thanks for reading, happy independence,
-Mike


Very fitting, given the recent mentions of "dictatorship" and all :-)



___
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] Assignment expression and coding style: the while True case

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

On 05.07.2018 1:51, Victor Stinner wrote:

Hi,

Let's say that the PEP 572 (assignment expression) is going to be
approved. Let's move on and see how it can be used in the Python
stdlib.

I propose to start the discussion about "coding style" (where are
assignment expressions appropriate or not?) with the "while True"
case.

I wrote a WIP pull request to use assignment expressions in "while True":
https://github.com/python/cpython/pull/8095/files

In short, replace:

 while True:
 x = expr
 if not x:
 break
 ...
with:

 while (x := expr):
 ...

My question is now: for which "while True" patterns are the assignment
expression appropriate? There identified different patterns.


== Pattern 1, straighforward ==

while True:
 line = input.readline()
 if not line:
 break
 ...

IMHO here assingment expression is appropriate here. The code remains
straighfoward to read.

while (line := input.readline()):
 ...


== Pattern 2, condition ==

Condition more complex than just "not line":

while True:
 q = c//n
 if n <= q:
 break
 ...

replaced with:

while (q := c//n) < n:
 ...

IMHO it's still acceptable to use assignement expression... Maybe only
for basic conditions? (see above)


== Pattern 3, double condition ==

while True:
 s = self.__read(1)
 if not s or s == NUL:
 break
 

replaced with:

while (s := self.__read(1)) and s != NUL:
 ...

Honestly, here, I don't know if it's appropriate...

At the first look, "s != NUL" is surprising, since "s" is not defined
before the while, it's only defined in the first *test* (defining a
variable inside a test is *currently* uncommon in Python).


== Pattern 4, while (...): pass ==

Sometimes, the loop body is replaced by "pass".

while True:
 tarinfo = self.next()
 if tarinfo is None:
 break

replaced with:

while (tarinfo := self.next()) is not None:
 pass

It reminds me the *surprising* "while (func());" or "while (func())
{}" in C (sorry for theorical C example, I'm talking about C loops
with an empty body).

Maybe it's acceptable here, I'm not sure.

Would be more readable with a more descriptive variable name:

while (chunk := self.next()) is not None:
pass
tarinfo = chunk



Note: such loop is rare (see my PR).


== Pattern 5, two variables ==

while True:
 m = match()
 if not m:
 break
 j = m.end()
 if i == j:
 break
 ...

replaced with:

while (m := match()) and (j := m.end()) == i:
 ...

Maybe we reached here the maximum acceptable complexity of a single
Python line? :-)

Would be more readable with additional parentheses:

while (m := match()) and ((j := m.end()) == i):




== Other cases ==

I chose to not use assignment expressions for the following while loops.

(A)

while True:
 name, token = _getname(g)
 if not name:
 break
 ...

"x, y := ..." is invalid. It can be tricked using "while (x_y :=
...)[0]: x, y = x_y; ...". IMHO it's not worth it.

(B)

while True:
 coeff = _dlog10(c, e, places)
 # assert len(str(abs(coeff)))-p >= 1
 if coeff % (5*10**(len(str(abs(coeff)))-p-1)):
 break
 places += 3

NOT replaced with:

while not (coeff := _dlog10(c, e, places)) % (5*10**(len(str(abs(coeff)))-p-1)):
 places += 3

^-- Tim Peters, I'm looking at you :-)

coeff is defined and then "immediately" used in "y" expression of
x%y... Yeah, it's valid code, but it looks too magic to me...

(C)

while True:
 chunk = self.raw.read()
 if chunk in empty_values:
 nodata_val = chunk
 break
 ...

"nodata_val = chunk" cannot be put into the "chunk := self.raw.read()"
assignment expression combined with a test. At least, I don't see how.
(D)

while 1:
 u1 = random()
 if not 1e-7 < u1 < .999:
 continue
 ...

Again, I don't see how to use assignment expression here.
Here, unlike the previous example, the assignment is a subexpression of 
the conditions, so it _can_ be inlined:


while  (u1:=random()) < 1e-7 or u1 > .999:


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/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] Assignment expression and coding style: the while True case

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



On 05/07/2018 00:15, Nathaniel Smith wrote:

On Wed, Jul 4, 2018 at 3:51 PM, Victor Stinner  wrote:

My question is now: for which "while True" patterns are the assignment
expression appropriate? There identified different patterns.


== Pattern 1, straighforward ==

while True:
 line = input.readline()
 if not line:
 break
 ...

IMHO here assingment expression is appropriate here. The code remains
straighfoward to read.

while (line := input.readline()):
 ...

There are some obvious caveats here – no-one has real experience with
:= yet, so any opinions right now are informed guesswork that will
probably change some if/when we get more experience with it.

Of course, this is absolutely true.  But ...

  Also, the
stdlib is a big place, and it seems inevitable that maintainers of
different modules will have different preferences. So I don't think it
makes sense to try to define some Official Universal Rule about when
:= is appropriate and when it isn't.

That said, FWIW, my current feeling is that this simplest case is the
only one where I would use :=; for your other examples I'd stick with
the loop-and-a-half style.
... even you, Nathaniel (correct me if I'm wrong, but you seem to be 
generally against PEP 572) would use := in (at least) one case.
I predict:  We'll all end up loving Assignment Expressions (like 
f-strings) once we've got used to them.  Or just taking them for 
granted.  No doubt some of us will use them more than others, some 
perhaps not at all.

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] Assignment expression and coding style: the while True case

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



On 05/07/2018 01:25, Tim Peters wrote:


== Pattern 5, two variables ==

while True:
    m = match()
    if not m:
        break
    j = m.end()
    if i == j:
        break
    ...

replaced with:

while (m := match()) and (j := m.end()) == i:


I assume (sorry to be pedantic :-)) this is a typo for
        while (m := match()) and (j := m.end()) != i:


    ...

Maybe we reached here the maximum acceptable complexity of a single
Python line? :-)


It's at my limit.  But, as in an earlier example, I'd be tempted to do 
"the obvious part":


    while m:= match():
        j = m.end()
        if i == j::
            break

Then the start reads like "while there's something _to_ look at::" and 
the body of the loop is happily guaranteed that there is.


.
Or you could compromise with this "intermediate density" version that 
does two "obvious parts":


    while m:=match():
        if  (j:=m.end()) == i:
            break

(or as I might write it

    while m:=match():
        if  (j:=m.end()) == i:  break

).
Some might prefer this as shorter than non-AE version but less dense 
than the one-liner.  Others might not. /De gustibus non est disputandum./
My conclusion:  Assignment expressions are - like any other Python 
feature - a tool, to be used with discretion and judgement.  Not the 
start of a competition to see who can write the most slick/unreadable code.

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] Assignment expression and coding style: the while True case

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

On 05.07.2018 3:36, Chris Angelico wrote:

On Thu, Jul 5, 2018 at 10:33 AM, Victor Stinner  wrote:

2018-07-05 2:15 GMT+02:00 Chris Angelico :

On Thu, Jul 5, 2018 at 10:03 AM, Victor Stinner  wrote:

On the 3360 for loops of the stdlib (*), I only found 2 loops which
would benefit of assignment expressions.

It's not easy to find loops which:
- build a list,
- are simple enough to be expressed as list comprehension,
- use a condition (if),
- use an expression different than just a variable name as the list
value (value appended to the list).

Are you implying that the above conditions are essential for
assignment expressions to be useful, or that this defines one
particular way in which they can be of value?

Hum, maybe I wasn't specific enough. I'm looking for "for loops" and
list comprehensions in stdlib which *can be* written using assignment
expression, like:

[var for ... in ... if (var := expr)].

I'm not discussing if such change is worth it or not. I just counted
how many for loops/list comprehensions *can* be modified to use
assingment expressions in the stdlib.

Maybe I missed some loops/comprehensions, and I would be happy to see
more examples ;-)

Cool. So you're looking for ones that fit a particular pattern that
can benefit, but there are almost certainly other patterns out there.
Just making sure that you weren't trying to say "out of 3360 loops,
exactly 3358 of them absolutely definitely cannot be improved here".
Well, if no-one knows how to find something that can be improved, it 
can't be improved :)

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/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] Assignment expression and coding style: the while True case

2018-07-04 Thread MRAB

On 2018-07-05 01:11, Victor Stinner wrote:

The code comes from Lib/_pyio.py. Simplified code:
---
nodata_val = b""
...
if n is None or n == -1:
 ...
 current_size = 0
 while True:
 chunk = self.raw.read()
 if chunk in empty_values:
 nodata_val = chunk
 break
 current_size += len(chunk)
 chunks.append(chunk)
 return b"".join(chunks) or nodata_val

...
while avail < n:
 chunk = self.raw.read(wanted)
 if chunk in empty_values:
 nodata_val = chunk
 break
 avail += len(chunk)
 chunks.append(chunk)

...
return out[:n] if out else nodata_val
---

It seems like "nodata_val = " assignment can be moved out of the first
loop, but cannot be moved for the second loop (since the second loop
has no iteration if "avail >= n").

Yeah, maybe for this specific file, assignment expressions could be
used for the (C) case and would be worth it.
In this case, the second loop might be better left as-is because there 
are 2 conditions for leaving the loop. Stylistically, it might be 
starting to hurt readability with something like:


while avail < n or (chunk := self.raw.read(wanted)) not in empty_values:

[snip]

___
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] Don't assign to a variable used later in the expression

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

On 05.07.2018 3:40, Ivan Pozdeev via Python-Dev wrote:

On 05.07.2018 2:29, Nathaniel Smith wrote:

On Wed, Jul 4, 2018 at 4:10 PM, Ivan Pozdeev via Python-Dev
  wrote:

On 04.07.2018 10:10, Nathaniel Smith wrote:

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.

I may have a fix to this:

Do not recommend assigning to the variable that is used later in the
expression.

This would rule out all the comprehension use cases.

Only those outside of the outermost iterable.
Scratch this line, it was from an earlier edit of the letter. I 
invalidate this myself further on.

I'd be fine with that personally. Reading through the PEP again I see
that there are more examples of them than I previously realized,
inside the semantics discussion and... well, this may be a personal
thing but for me they'd all be better described as "incomprehensions".
But, nonetheless, the comprehension use cases are supposed to be a
core motivation for the whole PEP.


Far from it. If/while, too. Any construct that accepts an expression 
and uses its result but doesn't allow to insert an additional line in 
the middle qualifies.

Also, some of the main arguments
for why a full-fledged := is better than the more limited alternative
proposals rely on using a variable on the same line where it's
assigned (e.g. Tim's gcd example). So I don't see this recommendation
getting any official traction within PEP 572 or PEP 8.

That's actually a valid use case!
In the aforementioned example,
if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
 return g
 the variable `diff' doesn't exist before, so there's no confusion 
which value is used.



Okay, I stay corrected:

_Do not recommend *changing* a variable that is used later in the 
expression._


I.e. the variable should not exist before assignment (or effectively 
not exist -- i.e. the old value should not be used).



E.g., good:

    [ rem for x in range(10) if rem := x%5 ]

bad:

    [ sum_ for x in range(10) if (sum_ := sum_ + x) % 5 ] # good 
luck figuring out what sum_ will hold




Of course you're free to use whatever style rules you prefer locally –
python-dev has nothing to do with that.

-n



--
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/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] PEP 572, VF/B, and "Shark Jumping"

2018-07-04 Thread Steven D'Aprano
On Wed, Jul 04, 2018 at 04:52:54PM -0700, Mike Miller wrote:

> Additionally, I have noticed a dichotomy between prolific "C programmers" 
> who've supported this PEP and many Python programmers who don't want it.  

Prolific C programmers like me, hey?

*shakes head in a combination of amusement and bemusement*


-- 
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] PEP 572 semantics

2018-07-04 Thread Tim Peters
[Steve Dower]

> In that case, please provide more examples of how it should work when
> the assignment expression appears to define a variable in a scope that
> is not on the call stack.
>

Sorry, I'm not clear what you're asking about.  Python's scopes are
determined statically, at compile-time - they have nothing directly to do
with what's on the call stack at runtime.  This PEP doesn't change anything
about that, either.


Whether intentional or not, there will be changes to how and when names
> are resolved.


Assignment expressions don't currently exist, so it's not possible to
change how their targets' names get resolved ;-)  If the resolution of any
_other_ names got changed, that would be a bug, not an unintended
consequence.



> The specification should provide enough information to
> determine the preferred behaviour, so we can tell the difference between
> intention changes and implementation bugs.
>
> For example, what should be returned from this function?
>

Thanks!  This clearly requires examples to flesh it out.


>
> >>> A = 0
> >>> def f(x):
> ... if x:
> ... [A := i for i in [1]]
> ... return A
>
> It depends on how it's called.  `A` is local to `f` in any case (your
global `A` is wholly irrelevant here)..  f(x) would raise UnboundLocalError
if `x` is not truthy, and return 1 if `x` is truthy.


> As far as I can tell, the closest current equivalent will not compile:
>
> >>> A = 0
> >>> def f(x):
> ... if x:
> ... def g():
> ... nonlocal A
> ... A = 1
> ... g()
> ... return A
> ...
>   File "", line 4
> SyntaxError: no binding for nonlocal 'A' found
>

That's because it's an incorrect translation:  the "if the name is
otherwise unknown in the containing block, establish it as local in the
containing block" requires code in a "by hand" translation to force that to
be the case.  "Otherwise unknown" means "is not declared global or nonlocal
in the block, and is not already known to be local to the block".

Because `A` isn't assigned to in the body of `f` outside the listcomp,
CPython _today_ has no idea `A` is intended to be local to `f`, so a
by-hand translation requires adding silly cruft to force `A` to be
recognized as local to `f`.  Perhaps the easiest "covers all cases" way:

def f(x):
if 0:  # NEW CODE HERE
A = None # AND HERE
if x:
   # etc

That doesn't generate any code at all in CPython (the optimizer throws away
the entire "if 0:" block)..  But compile-time analysis _does_ see the "A =
None" binding before the code is thrown away, and that's enough to
establish that `A` is local to `f`.  Then it compiles fine today, and:

>>> f(0)
Traceback (most recent call last):

return A
UnboundLocalError: local variable 'A' referenced before assignment
>>> f(1)
1


> Is this the equivalent behaviour you want?


No, `A` is local to `f` - no compile-time error is appropriate here.


> Or do you want an
> UnboundLocalError when calling f(0)?


Yup, because `A` is local to `f` but not bound at the time it's referenced.


> Or do you want the global A to be returned?


If and only if there was a `global A` declaration in `f`.


> How should we approach decision making about these cases as we
> implement this? The PEP does not provide enough information for me to
> choose the right behaviour here, and I argue that it should.
>
> Well, as before, the PEP pretty clearly (to me) already says that `A` is
local to `f`.  Everything else about the semantics follows from that.  But
also as in an earlier reply, I think the PEP could help by providing some
worked-out workalike-function examples.  The "if 0:" trick above isn't
deep, but it is too "clever" to be obvious.  Then again, it's not required
to _specify_ the semantics, only to illustrate one possible way of
_implementing_ the semantics.
___
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] Don't assign to a variable used later in the expression

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

On 05.07.2018 2:29, Nathaniel Smith wrote:

On Wed, Jul 4, 2018 at 4:10 PM, Ivan Pozdeev via Python-Dev
 wrote:

On 04.07.2018 10:10, Nathaniel Smith wrote:

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.

I may have a fix to this:

Do not recommend assigning to the variable that is used later in the
expression.

This would rule out all the comprehension use cases.

Only those outside of the outermost iterable.

I'd be fine with that personally. Reading through the PEP again I see
that there are more examples of them than I previously realized,
inside the semantics discussion and... well, this may be a personal
thing but for me they'd all be better described as "incomprehensions".
But, nonetheless, the comprehension use cases are supposed to be a
core motivation for the whole PEP.


Far from it. If/while, too. Any construct that accepts an expression and 
uses its result but doesn't allow to insert an additional line in the 
middle qualifies.

Also, some of the main arguments
for why a full-fledged := is better than the more limited alternative
proposals rely on using a variable on the same line where it's
assigned (e.g. Tim's gcd example). So I don't see this recommendation
getting any official traction within PEP 572 or PEP 8.

That's actually a valid use case!
In the aforementioned example,

if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
return g

 the variable `diff' doesn't exist before, so there's no confusion 
which value is used.



Okay, I stay corrected:

_Do not recommend *changing* a variable that is used later in the 
expression._


I.e. the variable should not exist before assignment (or effectively not 
exist -- i.e. the old value should not be used).



E.g., good:

    [ rem for x in range(10) if rem := x%5 ]

bad:

    [ sum_ for x in range(10) if (sum_ := sum_ + x) % 5 ] # good 
luck figuring out what sum_ will hold




Of course you're free to use whatever style rules you prefer locally –
python-dev has nothing to do with that.

-n



--
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] Assignment expression and coding style: the while True case

2018-07-04 Thread Chris Angelico
On Thu, Jul 5, 2018 at 10:33 AM, Victor Stinner  wrote:
> 2018-07-05 2:15 GMT+02:00 Chris Angelico :
>> On Thu, Jul 5, 2018 at 10:03 AM, Victor Stinner  wrote:
>>> On the 3360 for loops of the stdlib (*), I only found 2 loops which
>>> would benefit of assignment expressions.
>>>
>>> It's not easy to find loops which:
>>> - build a list,
>>> - are simple enough to be expressed as list comprehension,
>>> - use a condition (if),
>>> - use an expression different than just a variable name as the list
>>> value (value appended to the list).
>>
>> Are you implying that the above conditions are essential for
>> assignment expressions to be useful, or that this defines one
>> particular way in which they can be of value?
>
> Hum, maybe I wasn't specific enough. I'm looking for "for loops" and
> list comprehensions in stdlib which *can be* written using assignment
> expression, like:
>
>[var for ... in ... if (var := expr)].
>
> I'm not discussing if such change is worth it or not. I just counted
> how many for loops/list comprehensions *can* be modified to use
> assingment expressions in the stdlib.
>
> Maybe I missed some loops/comprehensions, and I would be happy to see
> more examples ;-)

Cool. So you're looking for ones that fit a particular pattern that
can benefit, but there are almost certainly other patterns out there.
Just making sure that you weren't trying to say "out of 3360 loops,
exactly 3358 of them absolutely definitely cannot be improved here".

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] Assignment expression and coding style: the while True case

2018-07-04 Thread Victor Stinner
2018-07-05 2:15 GMT+02:00 Chris Angelico :
> On Thu, Jul 5, 2018 at 10:03 AM, Victor Stinner  wrote:
>> On the 3360 for loops of the stdlib (*), I only found 2 loops which
>> would benefit of assignment expressions.
>>
>> It's not easy to find loops which:
>> - build a list,
>> - are simple enough to be expressed as list comprehension,
>> - use a condition (if),
>> - use an expression different than just a variable name as the list
>> value (value appended to the list).
>
> Are you implying that the above conditions are essential for
> assignment expressions to be useful, or that this defines one
> particular way in which they can be of value?

Hum, maybe I wasn't specific enough. I'm looking for "for loops" and
list comprehensions in stdlib which *can be* written using assignment
expression, like:

   [var for ... in ... if (var := expr)].

I'm not discussing if such change is worth it or not. I just counted
how many for loops/list comprehensions *can* be modified to use
assingment expressions in the stdlib.

Maybe I missed some loops/comprehensions, and I would be happy to see
more examples ;-)

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


[Python-Dev] "as" postfix notation highlights

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

On 04.07.2018 10:10, Nathaniel Smith wrote:


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.

If has stricken me that this is a highlight for the "as" syntax right here!

* Since it's a postfix, it preserves the forward reading order and is 
thus more fitting for inline syntax:


    while inv == (make_step(state, inv) as new_inv) and 
is_valid(new_inv): inv = new_inv


Makes it clear that in the first two cases, the old value of `inv' is 
used, and only after that, it's reassigned.


The prefix syntax of an assignment is instead read "from `=' on, then 
return to the start". This is okay for a standalone construct, but if 
embedded, the reading order becomes nontrivial:


    while inv == (new_inv := make_step(state, inv)) and 
is_valid(new_inv): inv = new_inv


* In the light of "Don't assign to a variable used later in the 
expression" , "as" looks completely different from assignment, which 
will deter folks from trying to do the problematic augmented assignments 
and demand expression syntax for them.



  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



--
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] PEP 572 semantics

2018-07-04 Thread Chris Angelico
On Thu, Jul 5, 2018 at 10:20 AM, Steve Dower  wrote:
> On 04Jul2018 1518, Tim Peters wrote:
>> The only new thing is specifying the scope of `a`, where "local to f"
>> means exactly the same thing as for any other name local to a function
>> today.  So far as the PEP semantics go, it doesn't even matter whether
>> an implementation _does_ implement some form of closure as such.  It
>> just has to provide the visible semantics of _lexically_ nested scopes
>> with indefinite extent, by whatever means it likes best.  That's what
>> "local to f" means (and has meant all along - well, since lexically
>> nested scopes were first introduced).
>
> In that case, please provide more examples of how it should work when
> the assignment expression appears to define a variable in a scope that
> is not on the call stack.

Using an assignment expression in a comprehension is the same as using
an assignment expression outside a comprehension at the exact same
point in the code. I'm not sure what else needs to be explained
further. It's assignment, so it creates a name at that scope.

> For example, what should be returned from this function?
>
> >>> A = 0
> >>> def f(x):
> ... if x:
> ... [A := i for i in [1]]
> ... return A

A would be local to f(). This will either return 1 or raise
UnboundLocalError; it will never return 0.

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] Assignment expression and coding style: the while True case

2018-07-04 Thread Tim Peters
[Victor Stinner]Let's say that the PEP 572 (assignment expression) is going
to be

> approved. Let's move on and see how it can be used in the Python stdlib.
>

Ugh - how adult ;-)


> I propose to start the discussion about "coding style" (where are
> assignment expressions appropriate or not?) with the "while True"
> case.
>
> I wrote a WIP pull request to use assignment expressions in "while True":
> https://github.com/python/cpython/pull/8095/files
>
> In short, replace:
>
> while True:
> x = expr
> if not x:
> break
> ...
> with:
>
> while (x := expr):


Better is to translate it to:

while x := expr:

That is, ;parentheses aren't needed in this context, and adding them anyway
will quickly look as strange here as, e.g.,

return (result)

already looks.  (Always requiring parens was rejected - see the PEP's "Always
requiring parentheses
" section).
   ...


> ...
> == Pattern 3, double condition ==
>
> while True:
> s = self.__read(1)
> if not s or s == NUL:
> break
> 
>
> replaced with:
>
> while (s := self.__read(1)) and s != NUL:
> ...
> Honestly, here, I don't know if it's appropriate...
>

Then leave it be!  My rule was "if it's not obviously better - at least a
little - don't use it".  This one is a wash (tie) to me, so I'd save the
bother of changing it.  Or just do the obvious part:

while s := self.__read(1):
if s == NUL:
break

No matter how the code may change in the future, the loop body surely
requires a non-empty `s` to stare at. and now the `while` header makes that
abundantly clear at a glance.

...

> == Pattern 4, while (...): pass ==
>
> Sometimes, the loop body is replaced by "pass".
>
> while True:
> tarinfo = self.next()
> if tarinfo is None:
> break
>
> replaced with:
>
> while (tarinfo := self.next()) is not None:
> pass
>
> It reminds me the *surprising* "while (func());" or "while (func())
> {}" in C (sorry for theorical C example, I'm talking about C loops
> with an empty body).
>
> Maybe it's acceptable here, I'm not sure.
>
> Note: such loop is rare (see my PR).
>

I decided "slight loss - don't bother" for most such in my own code.  At
least the first spelling above cuts the number of statements in half.
Replacing random.py's

r = getrandbits(k)
while r >= n:
r = getrandbits(k)

with

while (r := getrandbits(k)) >= n:
pass

is more attractive, for eliminating a textually identical (except for
indentation) line.

== Pattern 5, two variables ==
>
> while True:
> m = match()
> if not m:
> break
> j = m.end()
> if i == j:
> break
> ...
>
> replaced with:
>
> while (m := match()) and (j := m.end()) == i:
> ...
>
> Maybe we reached here the maximum acceptable complexity of a single
> Python line? :-)
>

It's at my limit.  But, as in an earlier example, I'd be tempted to do "the
obvious part":

while m:= match():
j = m.end()
if i == j::
break

Then the start reads like "while there's something _to_ look at::" and the
body of the loop is happily guaranteed that there is.

...

> I chose to not use assignment expressions for the following while loops.
>
> (A)
>
> while True:
> name, token = _getname(g)
> if not name:
> break
> ...
>
> "x, y := ..." is invalid. It can be tricked using "while (x_y :=...)[0]:
> x, y = x_y; ...". IMHO it's not worth it.


Indeed, it's quite worth _not_ doing it :-)



> (B)
>
> while True:
> coeff = _dlog10(c, e, places)
> # assert len(str(abs(coeff)))-p >= 1
> if coeff % (5*10**(len(str(abs(coeff)))-p-1)):
> break
> places += 3
>
> NOT replaced with:
>
> while not (coeff := _dlog10(c, e, places)) %
> (5*10**(len(str(abs(coeff)))-p-1)):
> places += 3
>
> ^-- Tim Peters, I'm looking at you :-)
>

Not my code ;-) - and it's _already_ too "busy" to be my code.  The
`5*10**...` part is already crying to be broken into simpler pieces with a
comment explaining what the intent is.



> coeff is defined and then "immediately" used in "y" expression of
> x%y... Yeah, it's valid code, but it looks too magic to me...
>

And the code was already too dense to follow easily.

(C)
>
> while True:
> chunk = self.raw.read()
> if chunk in empty_values:
> nodata_val = chunk
> break
> ...
>
> "nodata_val = chunk" cannot be put into the "chunk := self.raw.read()"
> assignment expression combined with a test. At least, I don't see how.
>
> No need to strain, either!  If it's not obvious, don't bother.



> (D)
>
> while 1:
> u1 = random()
> if not 1e-7 < u1 < .999:
> continue
> ...
>
> Again, I don't see how to use assignment expression here.
>
> It could be, in context, but not for the outermost `while 1:`.

while 1:
while not 1e-7 < (u1 := random()) < 999:
pass
# 

Re: [Python-Dev] PEP 572, VF/B, and "Shark Jumping"

2018-07-04 Thread Chris Angelico
On Thu, Jul 5, 2018 at 9:52 AM, Mike Miller  wrote:
> Compromise:
>
> Fortunately there is a compromise design that is chosen often these days in
> new languages---restricting these assignments to if/while (potentially
> comp/gen) statements.  We can also reuse the existing "EXPR as NAME" syntax
> that already exists and is widely enjoyed.
>
> This compromise design:
>
> 1  Handles the most common cases (of a group of infrequent cases)
> 0  Doesn't handle more obscure cases.
> 1  No new syntax (through reuse)
> 1  Looks Pythonic as hell
> 1  Difficult to misuse, complexity capped
>
> Score: 4/5

PLEASE can people stop rehashing this one and go and read previous
discussions and the PEP? Your first point is a failure, not a success
- the "if expr as name:" syntax is able to handle only the tiniest
proportion of cases, because many MANY situations require a condition
after that. You can't write this, for instance:

if f(x) as spam < 0:
print(spam)

So it fails the first, fails the second, is identical on the third
(it's still new syntax, just reusing a keyword - that's no better than
":="), is dubious on the fourth (Python uses "as NAME" for things that
are quite different from this, so it's confusing), and scores a
definite win only on the fifth - it's hard to misuse because it's
nerfed to oblivion.

This is old news. It's not a compromise design - it's a failed
previous iteration that is already mentioned in the PEP.

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] PEP 572 semantics

2018-07-04 Thread Steve Dower
On 04Jul2018 1518, Tim Peters wrote:
> The only new thing is specifying the scope of `a`, where "local to f"
> means exactly the same thing as for any other name local to a function
> today.  So far as the PEP semantics go, it doesn't even matter whether
> an implementation _does_ implement some form of closure as such.  It
> just has to provide the visible semantics of _lexically_ nested scopes
> with indefinite extent, by whatever means it likes best.  That's what
> "local to f" means (and has meant all along - well, since lexically
> nested scopes were first introduced).

In that case, please provide more examples of how it should work when
the assignment expression appears to define a variable in a scope that
is not on the call stack.

Whether intentional or not, there will be changes to how and when names
are resolved. The specification should provide enough information to
determine the preferred behaviour, so we can tell the difference between
intention changes and implementation bugs.

For example, what should be returned from this function?

>>> A = 0
>>> def f(x):
... if x:
... [A := i for i in [1]]
... return A

As far as I can tell, the closest current equivalent will not compile:

>>> A = 0
>>> def f(x):
... if x:
... def g():
... nonlocal A
... A = 1
... g()
... return A
...
  File "", line 4
SyntaxError: no binding for nonlocal 'A' found

Is this the equivalent behaviour you want? Or do you want an
UnboundLocalError when calling f(0)? Or do you want the global A to be
returned? How should we approach decision making about these cases as we
implement this? The PEP does not provide enough information for me to
choose the right behaviour here, and I argue that it should.

Cheers,
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] Assignment expression and coding style: the while True case

2018-07-04 Thread Chris Angelico
On Thu, Jul 5, 2018 at 10:03 AM, Victor Stinner  wrote:
> On the 3360 for loops of the stdlib (*), I only found 2 loops which
> would benefit of assignment expressions.
>
> It's not easy to find loops which:
> - build a list,
> - are simple enough to be expressed as list comprehension,
> - use a condition (if),
> - use an expression different than just a variable name as the list
> value (value appended to the list).

Are you implying that the above conditions are essential for
assignment expressions to be useful, or that this defines one
particular way in which they can be of value? Your opening implies the
former, but I think the latter is more accurate here.

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] Assignment expression and coding style: the while True case

2018-07-04 Thread Victor Stinner
The code comes from Lib/_pyio.py. Simplified code:
---
nodata_val = b""
...
if n is None or n == -1:
...
current_size = 0
while True:
chunk = self.raw.read()
if chunk in empty_values:
nodata_val = chunk
break
current_size += len(chunk)
chunks.append(chunk)
return b"".join(chunks) or nodata_val

...
while avail < n:
chunk = self.raw.read(wanted)
if chunk in empty_values:
nodata_val = chunk
break
avail += len(chunk)
chunks.append(chunk)

...
return out[:n] if out else nodata_val
---

It seems like "nodata_val = " assignment can be moved out of the first
loop, but cannot be moved for the second loop (since the second loop
has no iteration if "avail >= n").

Yeah, maybe for this specific file, assignment expressions could be
used for the (C) case and would be worth it.

Victor

2018-07-05 1:49 GMT+02:00 MRAB :
> On 2018-07-04 23:51, Victor Stinner wrote:
> [snip]
>>
>> (C)
>>
>> while True:
>>  chunk = self.raw.read()
>>  if chunk in empty_values:
>>  nodata_val = chunk
>>  break
>>  ...
>>
>> "nodata_val = chunk" cannot be put into the "chunk := self.raw.read()"
>> assignment expression combined with a test. At least, I don't see how.
>>
> If that's the only 'break' in the loop, then you know that 'chunk' will have
> an 'empty' value after the loop, so you can change it to:
>
> while True:
> chunk = self.raw.read()
> if chunk in empty_values:
> break
> ...
> nodata_val = chunk
>
> which then leads to:
>
> while (chunk := self.raw.read()) not in empty_values:
> ...
> nodata_val = chunk
>
> [snip]
> ___
> 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/vstinner%40redhat.com
___
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] PEP 572, VF/B, and "Shark Jumping"

2018-07-04 Thread Mike Miller

Recently on Python-Dev:

On 2018-07-03 15:24, Chris Barker wrote:
> On Tue, Jul 3, 2018 at 2:51 PM, Chris Angelico  On Wed, Jul 4, 2018 at 7:37 AM, Serhiy Storchaka 
>
> > 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.


Python Audience - wants clarity:

Not sure I'd say that most users are not professionals, but one major strength 
of Python is its suitability as a teaching language, which enlarges the 
community every year.


Additionally, I have noticed a dichotomy between prolific "C programmers" who've 
supported this PEP and many Python programmers who don't want it.  While C-devs 
use this construct all the time, their stereotypical Python counterpart is often 
looking for simplicity and clarity instead.  That's why we're here, folks.



Value - good:

Several use cases are handled well by PEP 572.  However it has been noted that 
complexity must be capped voluntarily relatively early—or the cure soon becomes 
worse than the disease.



Frequency - not much:

The use cases for assignment-expressions are not exceedingly common, coming up 
here and there.  Their omission has been a very mild burden and we've done 
without for a quarter century.


Believe the authors agreed that it won't be used too often and won't typically 
be mis- or overused.



New Syntax - a high burden:

For years I've read on these lists that syntax changes must clear a high 
threshold of the (Value*Frequency)/Burden (or VF/B) ratio.


Likewise, a few folks have compared PEP 572 to 498 (f-strings) which some former 
detractors have come to appreciate.  Don't believe this comparison applies well, 
since string interpolation is useful a hundred times a day, more concise, clear, 
and runs faster than previous functionality.  Threshold was easily cleared there.



Conclusion:

An incongruous/partially redundant new syntax to perform existing functionality 
more concisely feels too low on the VF/B ratio IMHO.  Value is good though 
mixed, frequency is low, and burden is higher than we'd like, resulting in "meh" 
and binary reactions.


Indeed many modern languages omit this feature specifically in an effort to 
reduce complexity, ironically citing the success of Python in support.  Less is 
more.



Compromise:

Fortunately there is a compromise design that is chosen often these days in new 
languages---restricting these assignments to if/while (potentially comp/gen) 
statements.  We can also reuse the existing "EXPR as NAME" syntax that already 
exists and is widely enjoyed.


This compromise design:

1  Handles the most common cases (of a group of infrequent cases)
0  Doesn't handle more obscure cases.
1  No new syntax (through reuse)
1  Looks Pythonic as hell
1  Difficult to misuse, complexity capped

Score: 4/5

PEP 572:

1  Handles the most common cases (of a group of infrequent cases)
1  Handles even more obscure cases.
0  New syntax
0  Denser look: more colons, parens, expression last
0  Some potential for misuse, complexity uncapped

Score: 2/5


Thanks for reading, happy independence,
-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] Assignment expression and coding style: the while True case

2018-07-04 Thread Victor Stinner
On the 3360 for loops of the stdlib (*), I only found 2 loops which
would benefit of assignment expressions.

It's not easy to find loops which:
- build a list,
- are simple enough to be expressed as list comprehension,
- use a condition (if),
- use an expression different than just a variable name as the list
value (value appended to the list).

diff --git a/Lib/mailbox.py b/Lib/mailbox.py
index 056251dce0..dc61a3a8b6 100644
--- a/Lib/mailbox.py
+++ b/Lib/mailbox.py
@@ -1341,9 +1341,9 @@ class Babyl(_singlefileMailbox):
 if len(stops) < len(starts):
 stops.append(line_pos - len(linesep))
 starts.append(next_pos)
-labels = [label.strip() for label
-in
self._file.readline()[1:].split(b',')
-if label.strip()]
+labels = [slabel for label
+  in self._file.readline()[1:].split(b',')
+  if (slabel := label.strip())]
 label_lists.append(labels)
 elif line == b'\037' or line == b'\037' + linesep:
 if len(stops) < len(starts):

diff --git a/Lib/nntplib.py b/Lib/nntplib.py
index 5961a28ab7..a5d13e35be 100644
--- a/Lib/nntplib.py
+++ b/Lib/nntplib.py
@@ -843,11 +843,9 @@ class _NNTPBase:
   DeprecationWarning, 2)
 line_pat = re.compile('^([^ \t]+)[ \t]+(.*)$')
 resp, raw_lines = self._longcmdstring('XGTITLE ' + group, file)
-lines = []
-for raw_line in raw_lines:
-match = line_pat.search(raw_line.strip())
-if match:
-lines.append(match.group(1, 2))
+lines = [match.group(1, 2)
+ for raw_line in raw_lines
+ if (match := line_pat.search(raw_line.strip()))]
 return resp, lines

 def xpath(self, id):

(*) Command used to count the number of for loops in the stdlib:

$ grep '\bfor\b' Lib/*py
Lib/{asyncio,logging,multiprocessing}/*.py|grep -v '"""'|grep -v
"'''"|grep -v '\.py: *#'|wc -l
3360

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] Assignment expression and coding style: the while True case

2018-07-04 Thread MRAB

On 2018-07-04 23:51, Victor Stinner wrote:
[snip]

(C)

while True:
 chunk = self.raw.read()
 if chunk in empty_values:
 nodata_val = chunk
 break
 ...

"nodata_val = chunk" cannot be put into the "chunk := self.raw.read()"
assignment expression combined with a test. At least, I don't see how.

If that's the only 'break' in the loop, then you know that 'chunk' will 
have an 'empty' value after the loop, so you can change it to:


while True:
chunk = self.raw.read()
if chunk in empty_values:
break
...
nodata_val = chunk

which then leads to:

while (chunk := self.raw.read()) not in empty_values:
...
nodata_val = chunk

[snip]
___
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] Don't assign to a variable used later in the expression

2018-07-04 Thread Nathaniel Smith
On Wed, Jul 4, 2018 at 4:10 PM, Ivan Pozdeev via Python-Dev
 wrote:
> On 04.07.2018 10:10, Nathaniel Smith wrote:
>> 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.
>
> I may have a fix to this:
>
> Do not recommend assigning to the variable that is used later in the
> expression.

This would rule out all the comprehension use cases.

I'd be fine with that personally. Reading through the PEP again I see
that there are more examples of them than I previously realized,
inside the semantics discussion and... well, this may be a personal
thing but for me they'd all be better described as "incomprehensions".

But, nonetheless, the comprehension use cases are supposed to be a
core motivation for the whole PEP. Also, some of the main arguments
for why a full-fledged := is better than the more limited alternative
proposals rely on using a variable on the same line where it's
assigned (e.g. Tim's gcd example). So I don't see this recommendation
getting any official traction within PEP 572 or PEP 8.

Of course you're free to use whatever style rules you prefer locally –
python-dev has nothing to do with that.

-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] Assignment expression and coding style: the while True case

2018-07-04 Thread Nathaniel Smith
On Wed, Jul 4, 2018 at 3:51 PM, Victor Stinner  wrote:
> My question is now: for which "while True" patterns are the assignment
> expression appropriate? There identified different patterns.
>
>
> == Pattern 1, straighforward ==
>
> while True:
> line = input.readline()
> if not line:
> break
> ...
>
> IMHO here assingment expression is appropriate here. The code remains
> straighfoward to read.
>
> while (line := input.readline()):
> ...

There are some obvious caveats here – no-one has real experience with
:= yet, so any opinions right now are informed guesswork that will
probably change some if/when we get more experience with it. Also, the
stdlib is a big place, and it seems inevitable that maintainers of
different modules will have different preferences. So I don't think it
makes sense to try to define some Official Universal Rule about when
:= is appropriate and when it isn't.

That said, FWIW, my current feeling is that this simplest case is the
only one where I would use :=; for your other examples I'd stick with
the loop-and-a-half style.

-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


[Python-Dev] Don't assign to a variable used later in the expression

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

On 04.07.2018 10:10, Nathaniel Smith wrote:

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.


I may have a fix to this:

Do not recommend assigning to the variable that is used later in the 
expression.


And to facilitate that, do not make any strong guarantees about 
evaluation order -- making any such attempt a gamble.


I immediately saw those "total := total + item" as odd but couldn't 
quite point out why.
Now I see: it ignores the whole augmented assignment machinery thing, 
which will make people demand that next.
Making this a discouraged case will diminish valid use cases and lower 
the need for that.



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



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


[Python-Dev] Assignment expression and coding style: the while True case

2018-07-04 Thread Victor Stinner
Hi,

Let's say that the PEP 572 (assignment expression) is going to be
approved. Let's move on and see how it can be used in the Python
stdlib.

I propose to start the discussion about "coding style" (where are
assignment expressions appropriate or not?) with the "while True"
case.

I wrote a WIP pull request to use assignment expressions in "while True":
https://github.com/python/cpython/pull/8095/files

In short, replace:

while True:
x = expr
if not x:
break
...
with:

while (x := expr):
...

My question is now: for which "while True" patterns are the assignment
expression appropriate? There identified different patterns.


== Pattern 1, straighforward ==

while True:
line = input.readline()
if not line:
break
...

IMHO here assingment expression is appropriate here. The code remains
straighfoward to read.

while (line := input.readline()):
...


== Pattern 2, condition ==

Condition more complex than just "not line":

while True:
q = c//n
if n <= q:
break
...

replaced with:

while (q := c//n) < n:
...

IMHO it's still acceptable to use assignement expression... Maybe only
for basic conditions? (see above)


== Pattern 3, double condition ==

while True:
s = self.__read(1)
if not s or s == NUL:
break


replaced with:

while (s := self.__read(1)) and s != NUL:
...

Honestly, here, I don't know if it's appropriate...

At the first look, "s != NUL" is surprising, since "s" is not defined
before the while, it's only defined in the first *test* (defining a
variable inside a test is *currently* uncommon in Python).


== Pattern 4, while (...): pass ==

Sometimes, the loop body is replaced by "pass".

while True:
tarinfo = self.next()
if tarinfo is None:
break

replaced with:

while (tarinfo := self.next()) is not None:
pass

It reminds me the *surprising* "while (func());" or "while (func())
{}" in C (sorry for theorical C example, I'm talking about C loops
with an empty body).

Maybe it's acceptable here, I'm not sure.

Note: such loop is rare (see my PR).


== Pattern 5, two variables ==

while True:
m = match()
if not m:
break
j = m.end()
if i == j:
break
...

replaced with:

while (m := match()) and (j := m.end()) == i:
...

Maybe we reached here the maximum acceptable complexity of a single
Python line? :-)


== Other cases ==

I chose to not use assignment expressions for the following while loops.

(A)

while True:
name, token = _getname(g)
if not name:
break
...

"x, y := ..." is invalid. It can be tricked using "while (x_y :=
...)[0]: x, y = x_y; ...". IMHO it's not worth it.

(B)

while True:
coeff = _dlog10(c, e, places)
# assert len(str(abs(coeff)))-p >= 1
if coeff % (5*10**(len(str(abs(coeff)))-p-1)):
break
places += 3

NOT replaced with:

while not (coeff := _dlog10(c, e, places)) % (5*10**(len(str(abs(coeff)))-p-1)):
places += 3

^-- Tim Peters, I'm looking at you :-)

coeff is defined and then "immediately" used in "y" expression of
x%y... Yeah, it's valid code, but it looks too magic to me...

(C)

while True:
chunk = self.raw.read()
if chunk in empty_values:
nodata_val = chunk
break
...

"nodata_val = chunk" cannot be put into the "chunk := self.raw.read()"
assignment expression combined with a test. At least, I don't see how.

(D)

while 1:
u1 = random()
if not 1e-7 < u1 < .999:
continue
...

Again, I don't see how to use assignment expression here.

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] PEP 572 semantics

2018-07-04 Thread Tim Peters
[Steve Dower]
> Okay, so as far as the specification goes, saying "assignment

> > expressions in comprehensions get or create a cell variable in the

> > defining scope and update its value" satisfies me just fine (or some

> > other wording that more closely mirrors the actual behaviour - all my

> > work here is on my own compiler, not the actual CPython one, and I don't

> > know that they're identical).

> >

> > I don't think this should be left assumed by the PEP. If it's likely to

> > be a restriction on other implementations to say "cell variable", then

> > say "For example, in CPython, ..."

The problem:  nothing about Python's scoping is changed by this PEP, so
saying anything related to the implementation of scoping risks giving a
misleading impression that something about scoping _is_ being changed.

The PEP certainly needs to define the intended scope of
assignment-expression targets in all cases.  It already tried, with perhaps
too few words.  But it strikes me as counterproductive to go on to say
anything about how scopes are implemented.  If, e.g., the PEP is clear that
in

def f():
return (a := i for i in range(5))

`a` is local to `f` and `i` is local to a directly nested scope, what's
left to the imagination?  Well, the implementations of scopes and
closures.  None of which the PEP changes.  The semantics of `i` haven't
changed from what we already have, neither the visibility nor extent of the
generator expression object returned.

The only new thing is specifying the scope of `a`, where "local to f" means
exactly the same thing as for any other name local to a function today.  So
far as the PEP semantics go, it doesn't even matter whether an
implementation _does_ implement some form of closure as such.  It just has
to provide the visible semantics of *lexically* nested scopes with
indefinite extent, by whatever means it likes best.  That's what "local to
f" means (and has meant all along - well, since lexically nested scopes
were first introduced).

Would it help to say "and by 'local to f' we mean the same thing we meant
before this PEP was written"?  Probably not ;-)  If someone doesn't know
what "name N belongs to scope S" means, that needs to get a clear answer,
but it's a fundamental question that's quite independent of this particular
PEP.

That said, I bet it would be helpful to give some examples that show how
CPython intends to implement this stuff, via giving explicit nested
workalike Python functions decorated with scope declarations.  The
concreteness of that is helpful.  The eternal problem with that is finding
a way to stop readers from taking the "workalike functions" too literally
(e.g., "but i tried it and it doesn't generate exactly the same byte
code!").
___
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] Tone it down on Twitter?

2018-07-04 Thread Ivan Levkivskyi
Just to clarify, the club of three in _my_ twit are the three authors of
the PEP.

Also, how about you not telling me what to say?

--
Ivan



On 4 July 2018 at 16:48, Stefan Krah  wrote:

>
> Apparently I have made it into "club of three who don't care much about
> opinions of others" for the crime of a single +0.5 for PEP-572 without
> participating in the discussion at all (neither did Jason).
>
> https://twitter.com/SerhiyStorchaka/status/1014274554452209665
>
> This is a new high for Twitter gossip.  Well done.  Perhaps in the next
> vote
> the politbureau can indicate the intended outcome beforehand so we know how
> to vote.
>
>
>
> Thanks,
>
> Stefan Krah
>
>
>
> ___
> 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/
> levkivskyi%40gmail.com
>
___
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] Tone it down on Twitter?

2018-07-04 Thread Mark Lawrence

On 04/07/18 16:48, Stefan Krah wrote:


Apparently I have made it into "club of three who don't care much about
opinions of others" for the crime of a single +0.5 for PEP-572 without
participating in the discussion at all (neither did Jason).

https://twitter.com/SerhiyStorchaka/status/1014274554452209665

This is a new high for Twitter gossip.  Well done.  Perhaps in the next vote
the politbureau can indicate the intended outcome beforehand so we know how
to vote.



Thanks,

Stefan Krah





Quite frankly I don't give a hoot what gets said on twitter, as it 
appears to be reserved for morons like the current president of the USA.


--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

___
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] PEP 572 semantics

2018-07-04 Thread Steve Dower

On 04Jul2018 1021, Tim Peters wrote:
Same as now, `i` is local to the synthetic nested function created for 
the genexp.  The scope of `a` is determined by pretending the assignment 
occurred in the block containing the outermost (textually - static 
analysis) comprehension.  In this case, `a = anything` before the 
`return` would establish that `a` is local to `f`, so that's the 
answer:  `a` is local to `f`.  If `a` had been declared global in `f`, 
then `a` in the genexp would be the same global `a`.  And similarly if 
`a` had been declared nonlocal.in  `f`.


In all cases the scope resolution is inherited from the closest 
containing non-comprehension/genexp block, with the twist if that if a 
name is unknown in that block, the name is established as being local to 
that block.  So your example is actually the subtlest case.


Okay, so as far as the specification goes, saying "assignment 
expressions in comprehensions get or create a cell variable in the 
defining scope and update its value" satisfies me just fine (or some 
other wording that more closely mirrors the actual behaviour - all my 
work here is on my own compiler, not the actual CPython one, and I don't 
know that they're identical).


I don't think this should be left assumed by the PEP. If it's likely to 
be a restriction on other implementations to say "cell variable", then 
say "For example, in CPython, ..."



 > From the any()/all() examples, it seems clear that the target scope for
 > the assignment has to be referenced from the generator scope (but not
 > for other comprehension types, which can simply do one transfer of the
 > assigned name after fully evaluating all the contents).

I don't think that follows.  It _may_ in some cases.  For example,
[SNIP]
_While_ the list comprehension is executing, it needs to rebind f's `i` 
on each iteration so that the call to `g()` on each iteration can see 
`i`'s then-current value.


Good point. My statement above captures this nuance, as far as I'm 
concerned. (Same for the frame lifetime discussion, which I snipped).


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

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


[Python-Dev] Fwd: Examples for PEP 572

2018-07-04 Thread Stéfane Fermigier
On Wed, Jul 4, 2018 at 12:09 PM Chris Angelico  wrote:

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

What I'm claiming is that ~300 000 pupils in "seconde" (~ 10th grade in the
US, cf.
https://jeretiens.net/conversion-des-niveaux-scolaires-france-grande-bretagne-etats-unis/amp/
) are supposed to start learning (some basics of) Python this year during
their math classes, next year theses 300k pupils will be in 11th grade and
still be doing some Python, and next year they will be in 12th and pass
their baccalauréat (~ "high school diploma").

That's 1 millions pupils actively learning some Python in 2020, not
counting other categories of students ("classes prépa", engineering school,
etc.).

A majority of them will probably stop being involved with Python later, and
a small percentage will become "professional Python programmers".

I'm pretty dubious that these figures will correspond to the rest of
> the world,


It's probably similar to every country where Python is the recommended or
mandated language for teaching algorithmics or the basics of CS in school.
I have unfortunately no idea if there are any other countries in a similar
situation.

And dissimilar to countries where CS is not taught in schools, or another
language is used (Scratch or other block-languages are usually popular).

(Fun fact: before Python, the language that used to be taught in high
school in France, though only to a minority of students, used to be OCaml,
a language that was created by french academics in the 80s and 90s. Python
won because it's simpler and more mainstream.)

  S.


> 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/sfermigier%2Blists%40gmail.com
>


-- 
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 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] Tone it down on Twitter?

2018-07-04 Thread Antoine Pitrou


I was going to answer that I agree the language there is unwarranted,
but then it came to me that the best way to keep things civil is perhaps
not to discuss Twitter-emitted opinions back on python-dev.

Regards

Antoine.


On Wed, 4 Jul 2018 17:48:21 +0200
Stefan Krah  wrote:
> Apparently I have made it into "club of three who don't care much about
> opinions of others" for the crime of a single +0.5 for PEP-572 without
> participating in the discussion at all (neither did Jason).
> 
> https://twitter.com/SerhiyStorchaka/status/1014274554452209665
> 
> This is a new high for Twitter gossip.  Well done.  Perhaps in the next vote
> the politbureau can indicate the intended outcome beforehand so we know how
> to vote.
> 
> 
> 
> Thanks,
> 
> Stefan Krah
> 
> 
> 



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


[Python-Dev] Tone it down on Twitter?

2018-07-04 Thread Stefan Krah


Apparently I have made it into "club of three who don't care much about
opinions of others" for the crime of a single +0.5 for PEP-572 without
participating in the discussion at all (neither did Jason).

https://twitter.com/SerhiyStorchaka/status/1014274554452209665

This is a new high for Twitter gossip.  Well done.  Perhaps in the next vote
the politbureau can indicate the intended outcome beforehand so we know how
to vote.



Thanks,

Stefan Krah



___
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] PEP 572 semantics

2018-07-04 Thread Tim Peters
Just a quickie:

[Steve Dower]

> > The PEP uses the phrase "an assignment expression
> occurs in a comprehension" - what does this mean?

It's about static analysis of the source code, at compile-time, to
establish scopes.  So "occurs in" means your eyeballs see an assignment
expression in a comprehension.

> Does it occur when/where it is compiled, instantiated, or executed? This
> is important because where it occurs determines which scope will be
> modified. For sanity sake, I want to assume that it means compiled,

Probably ;-)  I just don't know _exactly_ what those distinctions mean to
you.

> but now what happens when that scope is gone?

Nothing new.  There's no new concept of "scope" here, which is why the PEP
doesn't say a whole lot about scope.

>
>  >>> def f():

> > ... return (a := i for i in range(5))

> > ...

Same as now, `i` is local to the synthetic nested function created for the
genexp.  The scope of `a` is determined by pretending the assignment
occurred in the block containing the outermost (textually - static
analysis) comprehension.  In this case, `a = anything` before the `return`
would establish that `a` is local to `f`, so that's the answer:  `a` is
local to `f`.  If `a` had been declared global in `f`, then `a` in the
genexp would be the same global `a`.  And similarly if `a` had been
declared nonlocal.in `f`.

In all cases the scope resolution is inherited from the closest containing
non-comprehension/genexp block, with the twist if that if a name is unknown
in that block, the name is established as being local to that block.  So
your example is actually the subtlest case.


> >>> list(f())

> > [0, 1, 2, 3, 4]   # or a new error because the scope has gone?

Function scopes in Python have "indefinite extent", and nothing about that
changes.  So, ya, that's the output - same as today if you changed your
example to delete the "a :=" part.

Internally, f's local `a` was left bound to 4, but there's no way to see
that here because the genexp has been run to exhaustion and
reference-counting has presumably thrown everything away by now.

>>> a

> ???

Same thing typing `a` would result in if you had never typed `list(f())`.

Here's a variation:

def f():

>yield (a := i for i in range(5))
   yield a

Then:

>>> g = f()
>>> list(next(g))
[0, 1, 2, 3, 4]
>>> next(g)
4

> I'll push back real hard on doing the assignment in the scope
> where the generator is executed:

> >

> > >>> def do_secure_op(name, numbers):

> > ... authorised = check_authorised(name)

This instance of `authorized` is local to `do_secure_op`.

> ... if not all(numbers):

> > ... raise ValueError()

> > ... if not authorised:

> > ... raise SecurityError()

> > ... print('You made it!')

> > ...

> > >>> do_secure_op('whatever', (authorised := i for i in [1, 2, 3]))

And this instance of `authorized` is a global (because the genexp appears
in top-level code, so its containing block is the module).  The two
instances have nothing to do with each other.

> You made it!

Yup - you did!

> >>> authorised

> > NameError: name 'authorised' is undefined

It would display 3 instead.


> From the any()/all() examples, it seems clear that the target scope for

> > the assignment has to be referenced from the generator scope (but not

> > for other comprehension types, which can simply do one transfer of the

> > assigned name after fully evaluating all the contents).

I don't think that follows.  It _may_ in some cases.  For example,

def f():
i = None # not necessary, just making i's scope obvious
def g(ignore):
return i+1
return [g(i := j) for j in range(3)]

_While_ the list comprehension is executing, it needs to rebind f's `i` on
each iteration so that the call to `g()` on each iteration can see `i`'s
then-current value.

> Will this reference keep the frame object alive for as
> long as the generator exists? Can it be a weak reference?
> Are assignments just going to be silently ignored when
> the frame they should assign to is gone? I'd like to see these
> clarified in the main text.

Here you're potentially asking questions about how closures work in Python
(in the most-likely case that an embedded assignment-statement target
resolves to an enclosing function-local scope), but the PEP doesn't change
anything about how closures already work.  Closures are implemented via
"cell objects", one per name, which already supply both "read" and "write"
access to both the owning and referencing scopes.

def f():
a = 42
return (a+1 for i in range(3))

That works fine today, and a cell object is used in the synthesized genexp
function to get read access to f's local `a`.  But references to `a` in `f`
_also_ use that cell object. - the thing that lives in f's frame isn't
really the binding for `a`, but a reference to the cell object that _holds_
a's current binding.  The cell object doesn't care whether f's frame goes
away (except that the cell 

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] PEP 572: Write vs Read, Understand and Control Flow

2018-07-04 Thread Steven D'Aprano
On Wed, Jul 04, 2018 at 03:36:18PM +0300, Ivan Pozdeev via Python-Dev wrote:
> On 04.07.2018 15:29, Victor Stinner wrote:
> >The PEP 572 has been approved, it's no longer worth it to discuss it ;-)
> >
> >Victor
> 
> As of now, https://www.python.org/dev/peps/pep-0572/ is marked as "draft".

https://mail.python.org/pipermail/python-dev/2018-July/154231.html

https://mail.python.org/pipermail/python-dev/2018-July/154247.html

The state of the published PEP has unfortunately lagged behind the state 
of the discussion, due to the overwhelming number of posts.



-- 
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] Comparing PEP 576 and PEP 580

2018-07-04 Thread Jeroen Demeyer

On 2018-07-04 03:31, INADA Naoki wrote:

I think both PEPs are relying on FASTCALL calling convention,
and can't be accepted until FASTCALL is stable & public.


First of all, the fact that FASTCALL has not been made public should
not prevent from discussing those PEPs and even making a
(provisional?) decision on them. I don't think that the precise
API of FASTCALL really matters that much.

More importantly, I don't think that you can separate making FASTCALL
public from PEP 576/580. As you noted in [1], making FASTCALL public 
means more than just documenting METH_FASTCALL.


In particular, a new API should be added for calling objects using the
FASTCALL convention. Here I mean both an abstract API for arbitrary
callables as well as a specific API for certain classes. Since PEP 580
(and possibly also PEP 576) proposes changes to the implementation of
FASTCALL, it makes sense to design the public API for FASTCALL after
it is clear which of those PEPs (if any) is accepted. If we fix the 
FASTCALL API now, it might not be optimal when either PEP 576 or PEP 580 
is accepted.


Jeroen.


[1] https://mail.python.org/pipermail/python-dev/2018-June/153956.html
___
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] PEP 572 semantics

2018-07-04 Thread Guido van Rossum
Thanks for thinking about the details! I want to answer all of these but
right now I have some social obligations so it may be a few days. I expect
the outcome of this investigation to result in an improved draft for PEP
572.

On Wed, Jul 4, 2018 at 7:29 AM Steve Dower  wrote:

> Now that it's a done deal, I am closely reviewing the semantics section
> of PEP 572. (I had expected one more posting of the final PEP, but it
> seems the acceptance came somewhere in a thread that was already muted.)
>
> Since there has been no final posting that I'm aware of, I'm referring
> to https://www.python.org/dev/peps/pep-0572/ as of about an hour before
> posting this (hopefully it doesn't take me that long).
>
> To be clear, I am *only* looking at the "Syntax and semantics" section.
> So if something has been written down elsewhere in the PEP, please take
> my questions as a request to have it referenced from this section. I
> also gave up on the discussion by the third python-dev thread - if there
> were things decided that you think I'm stupid for not knowing, it
> probably means they never made it into the PEP.
>
> = Syntax and Semantics
>
> Could we include the changes necessary to
> https://docs.python.org/3/reference/grammar.html in order to specify
> where these expressions are valid? And ideally check that they work.
> This may expose new exceptional cases, but will also clarify some of the
> existing ones, especially for those of us who write Python parsers.
>
> == Exceptional cases
>
> Are the cases in the "Exceptional cases" section supposed to raise
> SyntaxError on compilation? That seems obvious, but no harm in stating
> it. (FWIW, I'd vote to ban the "bad" cases in style guides or by forcing
> parentheses, rather than syntactically. And for anyone who wonders why
> that's different from my position on slashes in f-strings, it's because
> I don't think we can ever resolve these cases but I hope that one day we
> can fix f-string slashes :) )
>
> == Scope of the target
>
> The PEP uses the phrase "an assignment expression occurs in a
> comprehension" - what does this mean? Does it occur when/where it is
> compiled, instantiated, or executed? This is important because where it
> occurs determines which scope will be modified. For sanity sake, I want
> to assume that it means compiled, but now what happens when that scope
> is gone?
>
> >>> def f():
> ... return (a := i for i in range(5))
> ...
> >>> list(f())
> [0, 1, 2, 3, 4]   # or a new error because the scope has gone?
> >>> a
> ???
>
> I'll push back real hard on doing the assignment in the scope where the
> generator is executed:
>
> >>> def do_secure_op(name, numbers):
> ... authorised = check_authorised(name)
> ... if not all(numbers):
> ... raise ValueError()
> ... if not authorised:
> ... raise SecurityError()
> ... print('You made it!')
> ...
> >>> do_secure_op('whatever', (authorised := i for i in [1, 2, 3]))
> You made it!
> >>> authorised
> NameError: name 'authorised' is undefined
>
> From the any()/all() examples, it seems clear that the target scope for
> the assignment has to be referenced from the generator scope (but not
> for other comprehension types, which can simply do one transfer of the
> assigned name after fully evaluating all the contents). Will this
> reference keep the frame object alive for as long as the generator
> exists? Can it be a weak reference? Are assignments just going to be
> silently ignored when the frame they should assign to is gone? I'd like
> to see these clarified in the main text.
>
>
> When an assignment is "expressly invalid" due to avoiding "edge cases",
> does this mean we should raise a SyntaxError? Or a runtime error? I'm
> not sure how easily these can be detected by our current compiler (or
> runtime, for that matter), but in the other tools that I work on it
> isn't going to be a trivial check.
>
> Also, I'm not clear at all on why [i := i+1 for i in range(5)] is a
> problem? Similarly for the other examples here. There's nothing wrong
> with `for i in range(5): i = i+1`, so why forbid this?
>
> == Relative precedence
>
> "may be used directly in a positional function call argument" - why not
> use the same syntax as generator expressions? Require parentheses unless
> it's the only argument. It seems like that's still got a TODO on it from
> one of the examples, so consider this a vote for matching
> generator-as-argument syntax.
>
>
> == Differences between assignment expressions
>
> I'm pretty sure the equivalent of "x = y = z = 0" would be "z := (y :=
> (x := 0))". Not that it matters when there are no side-effects of
> assignment (unless we decide to raise at runtime for invalid
> assignments), but it could become a point of confusion for people in the
> future to see it listed like this. Assignment expressions always
> evaluate from innermost to outermost.
>
> Gramatically, "Single assignment targets *other than* NAME are not
> supported" would be more 

Re: [Python-Dev] Checking that PEP 558 (defined semantics for locals()) handles assignment expressions

2018-07-04 Thread Guido van Rossum
Correct, there shouldn't be any additional corner cases for your PEP due to
inline assignments. We're not introducing new scopes nor other runtime
mechanisms; the target of an inline assignment is either a global or a cell
(nonlocal) defined at a specific outer level.

What I wish we had (quite independent from PEP 572) is a way in a debugger
to evaluate a comprehension that references a local in the current stack
frame. E.g. here's something I had in a pdb session yesterday:

(Pdb) p [getattr(context.context, x) for x in dir(context.context)]
*** NameError: name 'context' is not defined
(Pdb) global cc; cc = context
(Pdb) p [getattr(cc.context, x) for x in dir(cc.context)]
[, ]
(Pdb)

The first attempt failed because the outer `context` was a local variable
in some function, and pdb uses eval() to evaluate expressions.

On Wed, Jul 4, 2018 at 5:36 AM Nick Coghlan  wrote:

> With PEP 572's formal acceptance now expected to be just a matter of
> time, I'll limit any further personal expressions of opinion on the
> change and the process taken to achieve it to other venues :)
>
> However, there's a design aspect I do need to address, which is to
> make sure that PEP 558 (my proposal to actually nail down an
> implementation independent specification for how we expect locals() to
> behave at runtime) accurately covers the way runtimes and debuggers
> are expected to behave when comprehensions and generator expressions
> are executed at different scopes.
>
> My current view is that it's going to be OK to expose the differing
> behaviours at module and function scope directly:
>
> * if you debug a module level comprehension or genexp, the target name
> will be flagged on the code object as a dynamically resolved name
> reference, so a debugger should handle it the same was as it would
> handle any other "global NAME" declaration (and it will appear only in
> globals(), not in locals())
> * similarly for a function comprehension or genexp, the name will show
> up like any other "nonlocal NAME" (appears in locals() rather than
> globals(), and is affected by the proposed changes in the interaction
> between trace functions and the frame.f_locals attribute)
>
> I think that's an acceptable outcome, since it's a natural consequence
> of PEP 572 defining its comprehension and generator expression
> handling in terms of existing global and nonlocal scoping semantics.
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
> ___
> 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/guido%40python.org
>


-- 
--Guido van Rossum (python.org/~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 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


[Python-Dev] PEP 572 semantics

2018-07-04 Thread Steve Dower
Now that it's a done deal, I am closely reviewing the semantics section
of PEP 572. (I had expected one more posting of the final PEP, but it
seems the acceptance came somewhere in a thread that was already muted.)

Since there has been no final posting that I'm aware of, I'm referring
to https://www.python.org/dev/peps/pep-0572/ as of about an hour before
posting this (hopefully it doesn't take me that long).

To be clear, I am *only* looking at the "Syntax and semantics" section.
So if something has been written down elsewhere in the PEP, please take
my questions as a request to have it referenced from this section. I
also gave up on the discussion by the third python-dev thread - if there
were things decided that you think I'm stupid for not knowing, it
probably means they never made it into the PEP.

= Syntax and Semantics

Could we include the changes necessary to
https://docs.python.org/3/reference/grammar.html in order to specify
where these expressions are valid? And ideally check that they work.
This may expose new exceptional cases, but will also clarify some of the
existing ones, especially for those of us who write Python parsers.

== Exceptional cases

Are the cases in the "Exceptional cases" section supposed to raise
SyntaxError on compilation? That seems obvious, but no harm in stating
it. (FWIW, I'd vote to ban the "bad" cases in style guides or by forcing
parentheses, rather than syntactically. And for anyone who wonders why
that's different from my position on slashes in f-strings, it's because
I don't think we can ever resolve these cases but I hope that one day we
can fix f-string slashes :) )

== Scope of the target

The PEP uses the phrase "an assignment expression occurs in a
comprehension" - what does this mean? Does it occur when/where it is
compiled, instantiated, or executed? This is important because where it
occurs determines which scope will be modified. For sanity sake, I want
to assume that it means compiled, but now what happens when that scope
is gone?

>>> def f():
... return (a := i for i in range(5))
...
>>> list(f())
[0, 1, 2, 3, 4]   # or a new error because the scope has gone?
>>> a
???

I'll push back real hard on doing the assignment in the scope where the
generator is executed:

>>> def do_secure_op(name, numbers):
... authorised = check_authorised(name)
... if not all(numbers):
... raise ValueError()
... if not authorised:
... raise SecurityError()
... print('You made it!')
...
>>> do_secure_op('whatever', (authorised := i for i in [1, 2, 3]))
You made it!
>>> authorised
NameError: name 'authorised' is undefined

>From the any()/all() examples, it seems clear that the target scope for
the assignment has to be referenced from the generator scope (but not
for other comprehension types, which can simply do one transfer of the
assigned name after fully evaluating all the contents). Will this
reference keep the frame object alive for as long as the generator
exists? Can it be a weak reference? Are assignments just going to be
silently ignored when the frame they should assign to is gone? I'd like
to see these clarified in the main text.


When an assignment is "expressly invalid" due to avoiding "edge cases",
does this mean we should raise a SyntaxError? Or a runtime error? I'm
not sure how easily these can be detected by our current compiler (or
runtime, for that matter), but in the other tools that I work on it
isn't going to be a trivial check.

Also, I'm not clear at all on why [i := i+1 for i in range(5)] is a
problem? Similarly for the other examples here. There's nothing wrong
with `for i in range(5): i = i+1`, so why forbid this?

== Relative precedence

"may be used directly in a positional function call argument" - why not
use the same syntax as generator expressions? Require parentheses unless
it's the only argument. It seems like that's still got a TODO on it from
one of the examples, so consider this a vote for matching
generator-as-argument syntax.


== Differences between assignment expressions

I'm pretty sure the equivalent of "x = y = z = 0" would be "z := (y :=
(x := 0))". Not that it matters when there are no side-effects of
assignment (unless we decide to raise at runtime for invalid
assignments), but it could become a point of confusion for people in the
future to see it listed like this. Assignment expressions always
evaluate from innermost to outermost.

Gramatically, "Single assignment targets *other than* NAME are not
supported" would be more precise. And for specification's sake, does
"not supported" mean "is a syntax error"?

The "equivalent needs extra parentheses" examples add two sets of extra
parentheses. Are both required? Or just the innermost set?

---

Apologies for the lack of context. I've gone back and added the section
headings for as I read through this section.

Cheers,
Steve
___
Python-Dev mailing list
Python-Dev@python.org

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] Failing tests (on a Linux distro)

2018-07-04 Thread Matěj Cepl
On Wed, 2018-07-04 at 22:05 +1000, Nick Coghlan wrote:
> Running the following locally fails for me:
> 
> $ SOURCE_DATE_EPOCH=`date` ./python -m test test_py_compile
> test_compileall

Just if this is taken literally, it is wrong. According to https:
//reproducible-builds.org/specs/source-date-epoch/ it should be

$ SOURCE_DATE_EPOCH=`date +%s` ./python -m test test_py_compile \
test_compileall

Matěj

-- 
https://matej.ceplovi.cz/blog/, Jabber: mc...@ceplovi.cz
GPG Finger: 3C76 A027 CA45 AD70 98B5  BC1D 7920 5802 880B C9D8
 
And religious texts are a bit like software standards, the
interpretation is always the tricky and complicated bit.
-- Alan Cox

signature.asc
Description: This is a digitally signed message part
___
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] PEP 572: Write vs Read, Understand and Control Flow

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

On 04.07.2018 15:29, Victor Stinner wrote:

The PEP 572 has been approved, it's no longer worth it to discuss it ;-)

Victor


As of now, https://www.python.org/dev/peps/pep-0572/ is marked as "draft".


2018-07-04 13:21 GMT+02:00 Abdur-Rahmaan Janhangeer :

was going to tell

instead of := maybe => better

:= too close to other langs

Abdur-Rahmaan Janhangeer
https://github.com/Abdur-rahmaanJ


Of the proposed syntaxes, I dislike identifer := expression less, but

I'd still rather not see it added.
___
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/arj.python%40gmail.com

___
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


[Python-Dev] Checking that PEP 558 (defined semantics for locals()) handles assignment expressions

2018-07-04 Thread Nick Coghlan
With PEP 572's formal acceptance now expected to be just a matter of
time, I'll limit any further personal expressions of opinion on the
change and the process taken to achieve it to other venues :)

However, there's a design aspect I do need to address, which is to
make sure that PEP 558 (my proposal to actually nail down an
implementation independent specification for how we expect locals() to
behave at runtime) accurately covers the way runtimes and debuggers
are expected to behave when comprehensions and generator expressions
are executed at different scopes.

My current view is that it's going to be OK to expose the differing
behaviours at module and function scope directly:

* if you debug a module level comprehension or genexp, the target name
will be flagged on the code object as a dynamically resolved name
reference, so a debugger should handle it the same was as it would
handle any other "global NAME" declaration (and it will appear only in
globals(), not in locals())
* similarly for a function comprehension or genexp, the name will show
up like any other "nonlocal NAME" (appears in locals() rather than
globals(), and is affected by the proposed changes in the interaction
between trace functions and the frame.f_locals attribute)

I think that's an acceptable outcome, since it's a natural consequence
of PEP 572 defining its comprehension and generator expression
handling in terms of existing global and nonlocal scoping semantics.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
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] Failing tests (on a Linux distro)

2018-07-04 Thread Victor Stinner
Yes, see my issue https://bugs.python.org/issue34022 to discuss how to
fix tests.

Victor

2018-07-04 14:05 GMT+02:00 Nick Coghlan :
> On 4 July 2018 at 22:00, Nick Coghlan  wrote:
>> On 2 July 2018 at 17:38, Petr Viktorin  wrote:
>>> Anyway, the SUSE tests seem  to fail on .pyc files. The main change in that
>>> area was [PEP 552], try starting there. AFAIK, SUSE is ahead of Fedora in
>>> the reproducible builds area; perhaps that's where the difference is.
>>
>> In particular, if a build system sets SOURCE_DATE_EPOCH without
>> specifying a pyc format for py_compile or compileall, Python 3.7 will
>> give you checked hashes by default:
>> https://docs.python.org/3/library/py_compile.html?highlight=source_date_epoch#py_compile.compile
>
> Running the following locally fails for me:
>
> $ SOURCE_DATE_EPOCH=`date` ./python -m test test_py_compile 
> test_compileall
>
> So my guess would be that this is a test suite error where we're not
> handling the "running in a reproducible build environment with
> SOURCE_DATE_EPOCH already set" case.
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
> ___
> 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/vstinner%40redhat.com
___
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] PEP 572: Write vs Read, Understand and Control Flow

2018-07-04 Thread Victor Stinner
The PEP 572 has been approved, it's no longer worth it to discuss it ;-)

Victor

2018-07-04 13:21 GMT+02:00 Abdur-Rahmaan Janhangeer :
> was going to tell
>
> instead of := maybe => better
>
> := too close to other langs
>
> Abdur-Rahmaan Janhangeer
> https://github.com/Abdur-rahmaanJ
>
>> Of the proposed syntaxes, I dislike identifer := expression less, but
>>
>> I'd still rather not see it added.
>> ___
>> 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/arj.python%40gmail.com
___
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] Failing tests (on a Linux distro)

2018-07-04 Thread Nick Coghlan
On 4 July 2018 at 22:00, Nick Coghlan  wrote:
> On 2 July 2018 at 17:38, Petr Viktorin  wrote:
>> Anyway, the SUSE tests seem  to fail on .pyc files. The main change in that
>> area was [PEP 552], try starting there. AFAIK, SUSE is ahead of Fedora in
>> the reproducible builds area; perhaps that's where the difference is.
>
> In particular, if a build system sets SOURCE_DATE_EPOCH without
> specifying a pyc format for py_compile or compileall, Python 3.7 will
> give you checked hashes by default:
> https://docs.python.org/3/library/py_compile.html?highlight=source_date_epoch#py_compile.compile

Running the following locally fails for me:

$ SOURCE_DATE_EPOCH=`date` ./python -m test test_py_compile test_compileall

So my guess would be that this is a test suite error where we're not
handling the "running in a reproducible build environment with
SOURCE_DATE_EPOCH already set" case.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
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] Failing tests (on a Linux distro)

2018-07-04 Thread Nick Coghlan
On 2 July 2018 at 17:38, Petr Viktorin  wrote:
> Anyway, the SUSE tests seem  to fail on .pyc files. The main change in that
> area was [PEP 552], try starting there. AFAIK, SUSE is ahead of Fedora in
> the reproducible builds area; perhaps that's where the difference is.

In particular, if a build system sets SOURCE_DATE_EPOCH without
specifying a pyc format for py_compile or compileall, Python 3.7 will
give you checked hashes by default:
https://docs.python.org/3/library/py_compile.html?highlight=source_date_epoch#py_compile.compile

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
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] PEP 572: Write vs Read, Understand and Control Flow

2018-07-04 Thread Abdur-Rahmaan Janhangeer
agree for =>

but how many people use pascal eiffel etc? (go has a chance)

that's a reminder of an old, fading epoch, bland IDEs, hard-to-crunch fonts

BDL Guido once remarked in a pycon talk that today agencies would've
charged you a high price to tell you what the word python might tickle in
the subconscious of the common user, we should maybe write on what ":="
tickles in the mind of most programmers

Abdur-Rahmaan Janhangeer
https://github.com/Abdur-rahmaanJ
Mauritius

The fact that := will be familiar to many people (especially if they
> know Go, Pascal or Eiffel etc) is a point in its favour.
>
> https://en.wikipedia.org/wiki/Assignment_%28computer_science%29#Notation
>
> The => arrow puts the arguments around the "wrong" way compared to
> regular assignment:
>
> name = expression
> expression => name
>
> Although personally I like that order, many people did not and I think
> Guido ruled it out very early in the discussion.
>
> Also it may be too easily confused with <= or >= or the -> syntax from
> annotations.
>
___
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] PEP 572: Write vs Read, Understand and Control Flow

2018-07-04 Thread Steven D'Aprano
On Wed, Jul 04, 2018 at 03:21:29PM +0400, Abdur-Rahmaan Janhangeer wrote:
> was going to tell
> 
> instead of := maybe => better
> 
> := too close to other langs

The fact that := will be familiar to many people (especially if they 
know Go, Pascal or Eiffel etc) is a point in its favour.

https://en.wikipedia.org/wiki/Assignment_%28computer_science%29#Notation

The => arrow puts the arguments around the "wrong" way compared to 
regular assignment:

name = expression
expression => name

Although personally I like that order, many people did not and I think 
Guido ruled it out very early in the discussion.

Also it may be too easily confused with <= or >= or the -> syntax from 
annotations.



-- 
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] PEP 572: Write vs Read, Understand and Control Flow

2018-07-04 Thread Abdur-Rahmaan Janhangeer
was going to tell

instead of := maybe => better

:= too close to other langs

Abdur-Rahmaan Janhangeer
https://github.com/Abdur-rahmaanJ

Of the proposed syntaxes, I dislike identifer := expression less, but
>
I'd still rather not see it added.
> ___
> 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/arj.python%40gmail.com
>
___
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] PEP 572: Write vs Read, Understand and Control Flow

2018-07-04 Thread Christian Tismer
On 25.04.18 05:43, Steven D'Aprano wrote:
> On Tue, Apr 24, 2018 at 08:10:49PM -0500, Tim Peters wrote:
> 
>> Binding expressions are debugger-friendly in that they _don't_ just
>> vanish without a trace.  It's their purpose to _capture_ the values of
>> the expressions they name.  Indeed, you may want to add them all over
>> the place inside expressions, never intending to use the names, just
>> so that you can see otherwise-ephemeral intra-expression results in
>> your debugger ;-)
> 
> That's a fantastic point and I'm surprised nobody has thought of it 
> until now (that I've seen).
> 
> Chris, if you're still reading this and aren't yet heartedly sick and 
> tired of the PEP *wink* this ought to go in as another motivating point.


Yay, that's like a dream, really fantastic.

So sorry that I was way too deep in development in spring
and did not read earlier about that PEP.

I was actually a bit reluctant about "yet another way to prove
Python no longer simple" and now even that Pascal-ish look! :-)

But this argument has completely sold me. Marvellous!

-- 
Christian Tismer-Sperling:^)   tis...@stackless.com
Software Consulting  : http://www.stackless.com/
Karl-Liebknecht-Str. 121 : http://pyside.org
14482 Potsdam: GPG key -> 0xE7301150FB7BEE0E
phone +49 173 24 18 776  fax +49 (30) 700143-0023



signature.asc
Description: OpenPGP digital signature
___
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


  1   2   >