Re: [Python-Dev] PEP 572: Assignment Expressions -- intention to accept, near-final draft

2018-07-10 Thread Nick Coghlan
On 10 July 2018 at 11:00, Guido van Rossum  wrote:
> A lot has been said about PEP 572. I am planning to accept it soon,
> hopefully within a week. I realize I should have posted the draft from May
> 22 (when Tim and I were added as authors and it was significantly updated --
> see https://github.com/python/peps/pull/654). For this I apologize. Since
> then we've been diligently updating various details, tightening the spec
> without really changing the intended design.

Thanks for the updates, especially the new Appendix B that walks
through the comprehension scoping cases with worked examples.

I've submitted a couple of minor PRs, but this version of the PEP
looks solid to me, and makes the case for change well (I'm still only
a +0 personally, but I can also see myself some day saying "Yeah, that
turned out to be worth it in the long run")

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: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Jonathan Goble
On Tue, Jul 10, 2018 at 2:00 AM Terry Reedy  wrote:

> On 7/9/2018 9:00 PM, Guido van Rossum wrote:
> > We strongly prefer feedback in the form of Pull Requests to the peps
> > repo (the file is at
> > https://github.com/python/peps/blob/master/pep-0572.rst
> > ).
>
> I couple of people have said they don't know how to make pull requests
> against a PEP.  I believe the following works with the web editor.
>
> 1. Go to url above.
> 2. Click upper right pencil icon.  I don't know just who can do this.
> 3. Edit on the web page.  It might be easier to read the html and then
> use browser find to change anything seen.
> 4. Note that there are two scrollbars -- one for webpage and one for
> editing box.
> 5. At the bottom of the webpage, click 'Create a new branch for this
> commit and start a PR'.  This should unclick 'Commit directly to the
> master branch.'
> 6. Click Green [Propose file change] button.
> 7. I expect one will end up on the PR diff page.  If not, click 'files
> changed to get there.  Add comments explaining changes that need such.
>

This is almost precisely how I, a newbie to contributing, fixed a typo in
this PEP tonight. At step 2, anyone who is logged in can click the pencil
icon; if you don't have write access to the repo, GitHub automatically
forks the repo and commits your change to a new branch within your fork,
eliminating step 5.

The problem I see with this is that I don't know of any way to accept or
> reject the different proposed changes within the PR.  If there is, I
> would like to know how.
>

I don't believe there is a way to merge part of a PR. The rejected changes
would have to be reverted with a new commit prior to merging.

-- 
> 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/jcgoble3%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: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Terry Reedy

On 7/9/2018 9:00 PM, Guido van Rossum wrote:
We strongly prefer feedback in the form of Pull Requests to the peps 
repo (the file is at 
https://github.com/python/peps/blob/master/pep-0572.rst 
).


I couple of people have said they don't know how to make pull requests 
against a PEP.  I believe the following works with the web editor.


1. Go to url above.
2. Click upper right pencil icon.  I don't know just who can do this.
3. Edit on the web page.  It might be easier to read the html and then 
use browser find to change anything seen.
4. Note that there are two scrollbars -- one for webpage and one for 
editing box.
5. At the bottom of the webpage, click 'Create a new branch for this 
commit and start a PR'.  This should unclick 'Commit directly to the 
master branch.'

6. Click Green [Propose file change] button.
7. I expect one will end up on the PR diff page.  If not, click 'files 
changed to get there.  Add comments explaining changes that need such.


The problem I see with this is that I don't know of any way to accept or 
reject the different proposed changes within the PR.  If there is, I 
would like to know how.


--
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: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Guido van Rossum
On Mon, Jul 9, 2018 at 8:24 PM, Rob Cliffe via Python-Dev <
python-dev@python.org> wrote:

> I apologise for not replying in the form of a Pull Request - I don't know
> how to make one.
>
>
> On 10/07/2018 02:00, Guido van Rossum wrote:
>
>> Rationale
>> =
>>
>> Naming the result of an expression is an important part of programming,
>> allowing a descriptive name to be used in place of a longer expression,
>> and permitting reuse.  Currently, this feature is available only in
>> statement form, making it unavailable in list comprehensions and other
>> expression contexts.
>>
>

> I think the wording of the last sentence gives too much importance to list
> comprehensions (IMO influenced by the amount of discussion of the PEP that
> was related to list comprehensions, understandably since that was the case
> where the semantics were most debatable).  I would suggest
> "... making it unavailable in expression contexts."
> or maybe
> "... making it unavailable in expression contexts (including list
> comprehension)."
>

Hm, I don't think it's worth tweaking the text here. The PEP has some
choice things to say about comprehensions, and I don't mind calling them
out especially here. Also, when you need a temporary variable outside a
comprehension it's easy enough to rewrite the code a bit -- but for a
comprehension you'd have to refactor the whole comprehension away (into a
regular for-loop), which is a bit more effort.



> Another example illustrates that programmers sometimes do more work to
>> save an extra level of indentation::
>>
>> match1 = pattern1.match(data)
>> match2 = pattern2.match(data)
>> if match1:
>> return match1.group(1)
>> elif match2:
>> return match2.group(2)
>>
>> This code tries to match ``pattern2`` even if ``pattern1`` has a match
>> (in which case the match on ``pattern2`` is never used). The more
>> efficient rewrite would have been::
>>
>> match1 = pattern1.match(data)
>> if match1:
>> return match1.group(1)
>> else:
>> match2 = pattern2.match(data)
>> if match2:
>> return match2.group(2)
>>
> I suggest
> ... The more efficient rewrite would have been:
> match1 = pattern1.match(data)
> if match1:
> return match1.group(1)
> match2 = pattern2.match(data)
> if match2:
> return match2.group(2)
> (a more natural way to write it which avoids cascading indentation).
>

Hm, I think I might have simplified this a bit from the code I actually
found -- there might not have been a `return` in the original. I don't want
to break the `if...elif` pattern in the rewrite. I guess I'll rewrite it
using assignment to a variable instead of `return`.


> # Handle a matched regex
>> if (match := pattern.search(data)) is not None:
>> ...
>>
> I suggest
> # Handle a matched regex
> if (match := pattern.search(data)) is not None:
> # do something with match
> I think it is really important to make clear the benefit of the PEP here:
> that "match" is bound to a value and can be used subsequently.
>
> # A more explicit alternative to the 2-arg form of iter() invocation
>> while (value := read_next_item()) is not None:
>> ...
>>
> As the 2-arg form of iter() is not that well known, I suggest that the
> iter version is spelled out for contrast.  (Sorry, I can't quite work it
> what it would be.)
>

Hm, you have a point there. I was referring to

  for value in iter(read_next_item, None):
  ...

The example would be more convincing if there was an additional argument to
read_next_value(), since then the 2-arg iter() version would have required
a lambda. Maybe I shouldn't mention 2-arg iter here at all.


> # Share a subexpression between a comprehension filter clause and its
>> output
>> filtered_data = [y for x in data if (y := f(x)) is not None]
>>
> That's fine, but what about also having an example that illustrates,
> simply, the "permitting reuse" in an expression part of the Rationale, e.g.
> powers = [ (y := x+1), y**2, y**3, y**4 ]
> (I appreciate that this sort of overlaps with the section "Simplifying
> list comprehensions", but it seems to me to be such an important part of
> the Rationale that it should be illustrated here.)
>

I could add this (before the filtered_data example):

# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]



> Relative precedence of ``:=``
>> -
>>
>> The ``:=`` operator groups more tightly than a comma in all syntactic
>> positions where it is legal, but less tightly than all operators,
>> including ``or``, ``and`` and ``not``.
>>
> and presumably including "if" and "else", as in
> x := y if y else -1
> Might it be worth adding "if" and "else" to the list?
>

Good call, I'll add conditional expressions to the list.


> - Single assignment targets other than than a single ``NAME`` are
>>   not supported::
>>
>> # No equivalent
>>  

Re: [Python-Dev] PEP 572: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Glenn Linderman

On 7/9/2018 8:43 PM, Guido van Rossum wrote:



An exception to this special case applies when the target name is the
same as a loop control variable for a comprehension containing it.
This is invalid.  This exception exists to rule out edge cases of the
above scope rules as illustrated by ``[i := i+1 for i in range(5)]``
or ``[[(j := j) for i in range(5)] for j in range(5)]``. Note that
this exception also applies to ``[i := 0 for i, j in stuff]``, as
well
as to cases like ``[i+1 for i in i := stuff]``.



It is unclear whether exactly what is invalid. Is the use of the
target name that is the same as (any of the nested) loop control
variable invalid? I think, from discussions, that that is what is
meant. But this paragraph could be interpreted as meaning the
special case doesn't apply, meaning that the target name would be
in a "sublocal" scope.


Really? If it didn't say "this is invalid" I could see that "exception 
to the special case" might be interpreted as "the special case doesn't 
apply". But with "This is invalid" explicitly added I don't see how 
that interpretation could be valid. Is it clearer if I changed that to 
"Such code is invalid"? Or perhaps I should move "This is invalid" to 
the end of the paragraph?


That's better; even better might be to say what is invalid... instead of 
used pronoun.


"Use of any of the comprension loop control variables as a target name 
in an assignment expression is invalid."


It isn't really an exception to the special case, it is an exception to 
the general rule than any old name can be used as an assignment 
expression target, IIUC.
___
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: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Guido van Rossum
On Mon, Jul 9, 2018 at 7:40 PM, Glenn Linderman 
wrote:

> On 7/9/2018 6:00 PM, Guido van Rossum wrote:
>
>   This rule is included to simplify the choice for the user between an
>   assignment statements and an assignment expression -- there is no
>
>
> "statements" should not be plural in the above line.
>

Will fix.

  syntactic position where both are valid.
>
>
>
> An exception to this special case applies when the target name is the
> same as a loop control variable for a comprehension containing it.
> This is invalid.  This exception exists to rule out edge cases of the
> above scope rules as illustrated by ``[i := i+1 for i in range(5)]``
> or ``[[(j := j) for i in range(5)] for j in range(5)]``.  Note that
> this exception also applies to ``[i := 0 for i, j in stuff]``, as well
> as to cases like ``[i+1 for i in i := stuff]``.
>
>
>
> It is unclear whether exactly what is invalid. Is the use of the target
> name that is the same as (any of the nested) loop control variable invalid?
> I think, from discussions, that that is what is meant. But this paragraph
> could be interpreted as meaning the special case doesn't apply, meaning
> that the target name would be in a "sublocal" scope.
>

Really? If it didn't say "this is invalid" I could see that "exception to
the special case" might be interpreted as "the special case doesn't apply".
But with "This is invalid" explicitly added I don't see how that
interpretation could be valid. Is it clearer if I changed that to "Such
code is invalid"? Or perhaps I should move "This is invalid" to the end of
the paragraph?


> The ``:=`` operator groups more tightly than a comma in all syntactic
> positions where it is legal, but less tightly than all operators,
>
>
> If comma is considered an operator, this sentence is inconsistent, would
> need to be "all other operators".  Even if comma is not considered an
> operator, the sentence would be more clear with "other" added, since ":="
> is an operator.
>

Makes sense.

-- 
--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] PEP 572: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Rob Cliffe via Python-Dev
I apologise for not replying in the form of a Pull Request - I don't 
know how to make one.



On 10/07/2018 02:00, Guido van Rossum wrote:

Rationale
=

Naming the result of an expression is an important part of programming,
allowing a descriptive name to be used in place of a longer expression,
and permitting reuse.  Currently, this feature is available only in
statement form, making it unavailable in list comprehensions and other
expression contexts.
I think the wording of the last sentence gives too much importance to 
list comprehensions (IMO influenced by the amount of discussion of the 
PEP that was related to list comprehensions, understandably since that 
was the case where the semantics were most debatable).  I would suggest

"... making it unavailable in expression contexts."
or maybe
"... making it unavailable in expression contexts (including list 
comprehension)."



Another example illustrates that programmers sometimes do more work to
save an extra level of indentation::

    match1 = pattern1.match(data)
    match2 = pattern2.match(data)
    if match1:
    return match1.group(1)
    elif match2:
    return match2.group(2)

This code tries to match ``pattern2`` even if ``pattern1`` has a match
(in which case the match on ``pattern2`` is never used). The more
efficient rewrite would have been::

    match1 = pattern1.match(data)
    if match1:
    return match1.group(1)
    else:
    match2 = pattern2.match(data)
    if match2:
    return match2.group(2)

I suggest
... The more efficient rewrite would have been:
    match1 = pattern1.match(data)
    if match1:
    return match1.group(1)
    match2 = pattern2.match(data)
    if match2:
    return match2.group(2)
(a more natural way to write it which avoids cascading indentation).


    # Handle a matched regex
    if (match := pattern.search(data)) is not None:
    ...

I suggest
    # Handle a matched regex
    if (match := pattern.search(data)) is not None:
    # do something with match
I think it is really important to make clear the benefit of the PEP 
here: that "match" is bound to a value and can be used subsequently.



    # A more explicit alternative to the 2-arg form of iter() invocation
    while (value := read_next_item()) is not None:
    ...
As the 2-arg form of iter() is not that well known, I suggest that the 
iter version is spelled out for contrast.  (Sorry, I can't quite work it 
what it would be.)


    # Share a subexpression between a comprehension filter clause and 
its output

    filtered_data = [y for x in data if (y := f(x)) is not None]
That's fine, but what about also having an example that illustrates, 
simply, the "permitting reuse" in an expression part of the Rationale, e.g.

        powers = [ (y := x+1), y**2, y**3, y**4 ]
(I appreciate that this sort of overlaps with the section "Simplifying 
list comprehensions", but it seems to me to be such an important part of 
the Rationale that it should be illustrated here.)



Relative precedence of ``:=``
-

The ``:=`` operator groups more tightly than a comma in all syntactic
positions where it is legal, but less tightly than all operators,
including ``or``, ``and`` and ``not``.

and presumably including "if" and "else", as in
    x := y if y else -1
Might it be worth adding "if" and "else" to the list?



- Single assignment targets other than than a single ``NAME`` are
  not supported::

    # No equivalent
    a[i] = x
    self.rest = []

[snip]

- Iterable packing and unpacking (both regular or extended forms) are
  not supported::

    # Equivalent needs extra parentheses
    loc = x, y  # Use (loc := (x, y))
    info = name, phone, *rest  # Use (info := (name, phone, *rest))

    # No equivalent
    px, py, pz = position
    name, phone, email, *other_info = contact

[snip]
    total += tax  # Equivalent: (total := total + tax)
Is it conceivable that some of these restrictions might be removed in a 
future version of Python?  If so, the PEP might include a note to this 
effect.


Oh, and what I think are typos:

(Note that ``with EXPR as VAR`` does *not* simply assing the value
   of ``EXPR`` to ``VAR`` -- it calls ``EXPR.__enter__()`` and assigns
   the result of *that* to ``VAR``.)

    assing -> assign

(eg where the condition is ``f(x) < 0``

    eg -> e.g.

members of the core-mentorship mailing list

    core-mentorship -> core mentorship

is a vast improvment over the briefer::

    improvment -> improvement

Best wishes
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] PEP 572: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Glenn Linderman

On 7/9/2018 6:00 PM, Guido van Rossum wrote:

This rule is included to simplify the choice for the user between an
  assignment statements and an assignment expression -- there is no


"statements" should not be plural in the above line.


syntactic position where both are valid.




An exception to this special case applies when the target name is the
same as a loop control variable for a comprehension containing it.
This is invalid.  This exception exists to rule out edge cases of the
above scope rules as illustrated by ``[i := i+1 for i in range(5)]``
or ``[[(j := j) for i in range(5)] for j in range(5)]``.  Note that
this exception also applies to ``[i := 0 for i, j in stuff]``, as well
as to cases like ``[i+1 for i in i := stuff]``.



It is unclear whether exactly what is invalid. Is the use of the target 
name that is the same as (any of the nested) loop control variable 
invalid? I think, from discussions, that that is what is meant. But this 
paragraph could be interpreted as meaning the special case doesn't 
apply, meaning that the target name would be in a "sublocal" scope.




The ``:=`` operator groups more tightly than a comma in all syntactic
positions where it is legal, but less tightly than all operators,


If comma is considered an operator, this sentence is inconsistent, would 
need to be "all other operators".  Even if comma is not considered an 
operator, the sentence would be more clear with "other" added, since 
":=" is an operator.



Sorry, I haven't learned pull requests.
Glenn

___
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: Assignment Expressions -- intention to accept, near-final draft

2018-07-09 Thread Guido van Rossum
A lot has been said about PEP 572. I am planning to accept it soon,
hopefully within a week. I realize I should have posted the draft from May
22 (when Tim and I were added as authors and it was significantly updated
-- see https://github.com/python/peps/pull/654). For this I apologize.
Since then we've been diligently updating various details, tightening the
spec without really changing the intended design.

I know it is inevitable that there will be replies attempting to convince
us that a different syntax is better or that we shouldn't do this at all.
Please save your breath. Iv'e seen every possible such response before, and
they haven't convinced me. At this point we're just looking for feedback on
the text of the document, e.g. pointing out ambiguities or requests for
more clarity in some part of the spec, *not* for alternative designs or
passionate appeals to PEP 20.

Below is the latest draft. All three authors are happy with it. You can
also read the PEP online at https://www.python.org/dev/peps/pep-0572/. We
strongly prefer feedback in the form of Pull Requests to the peps repo (the
file is at https://github.com/python/peps/blob/master/pep-0572.rst).


PEP: 572
Title: Assignment Expressions
Author: Chris Angelico , Tim Peters ,
Guido van Rossum 
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 28-Feb-2018
Python-Version: 3.8
Post-History: 28-Feb-2018, 02-Mar-2018, 23-Mar-2018, 04-Apr-2018,
17-Apr-2018,
  25-Apr-2018, 09-Jul-2018


Abstract


This is a proposal for creating a way to assign to variables within an
expression using the notation ``NAME := expr``.

Pending Acceptance
--

This PEP will be accepted, however it needs some editing for clarity
and exact specification.  A final draft will be posted to python-dev.
Note that alternate syntax proposals ("EXPR as NAME", "EXPR given
...") are no longer under consideration.  Hopefully the final draft
will be posted well before the end of July 2018.


Rationale
=

Naming the result of an expression is an important part of programming,
allowing a descriptive name to be used in place of a longer expression,
and permitting reuse.  Currently, this feature is available only in
statement form, making it unavailable in list comprehensions and other
expression contexts.

Additionally, naming sub-parts of a large expression can assist an
interactive
debugger, providing useful display hooks and partial results. Without a way
to
capture sub-expressions inline, this would require refactoring of the
original
code; with assignment expressions, this merely requires the insertion of a
few
``name :=`` markers. Removing the need to refactor reduces the likelihood
that
the code be inadvertently changed as part of debugging (a common cause of
Heisenbugs), and is easier to dictate to another programmer.

The importance of real code
---

During the development of this PEP many people (supporters and critics
both) have had a tendency to focus on toy examples on the one hand,
and on overly complex examples on the other.

The danger of toy examples is twofold: they are often too abstract to
make anyone go "ooh, that's compelling", and they are easily refuted
with "I would never write it that way anyway".

The danger of overly complex examples is that they provide a
convenient strawman for critics of the proposal to shoot down ("that's
obfuscated").

Yet there is some use for both extremely simple and extremely complex
examples: they are helpful to clarify the intended semantics.
Therefore there will be some of each below.

However, in order to be *compelling*, examples should be rooted in
real code, i.e. code that was written without any thought of this PEP,
as part of a useful application, however large or small.  Tim Peters
has been extremely helpful by going over his own personal code
repository and picking examples of code he had written that (in his
view) would have been *clearer* if rewritten with (sparing) use of
assignment expressions.  His conclusion: the current proposal would
have allowed a modest but clear improvement in quite a few bits of
code.

Another use of real code is to observe indirectly how much value
programmers place on compactness.  Guido van Rossum searched through a
Dropbox code base and discovered some evidence that programmers value
writing fewer lines over shorter lines.

Case in point: Guido found several examples where a programmer
repeated a subexpression, slowing down the program, in order to save
one line of code, e.g. instead of writing::

match = re.match(data)
group = match.group(1) if match else None

they would write::

group = re.match(data).group(1) if re.match(data) else None

Another example illustrates that programmers sometimes do more work to
save an extra level of indentation::

match1 = pattern1.match(data)
match2 = pattern2.match(data)
if match1:
return match1.group(1)
elif match2:
return 

Re: [Python-Dev] PEP 572: Assignment Expressions

2018-05-01 Thread Chris Jerdonek
On Tue, May 1, 2018 at 2:14 AM, Steve Holden  wrote:
> On Tue, May 1, 2018 at 3:36 AM, Chris Jerdonek 
> wrote:
>>
>> On Thu, Apr 26, 2018 at 10:33 AM, Sven R. Kunze  wrote:
>> > On 25.04.2018 01:19, Steven D'Aprano wrote:
>> >>
>> >> Sorry, gcd(diff, n) is not the "perfect name", and I will tell you that
>> >> sometimes g is better. [...]
>> >
>> > We were talking about the real-world code snippet of Tim (as a
>> > justification
>> > of := ) and alternative rewritings of it without resorting to new
>> > syntax.
>>
>> Apologies if this idea has already been discussed (I might have missed
>> the relevant email), but thinking back to Tim's earlier example--
>>
>> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
>> return g
>>
>> it occurs to me this could be implemented with current syntax using a
>> pattern like the following:
>>
>> stashed = [None]
>>
>> def stash(x):
>> stashed[0] = x
>> return x
>>
>> if stash(x - x_base) and stash(gcd(stashed[0], n)) > 1:
>> return stashed[0]
>>
>> There are many variations to this idea, obviously. For example, one
>> could allow passing a "name" to stash(), or combine stash / stashed
>> into a single, callable object that allows setting and reading from
>> its store. I wonder if one of them could be made into a worthwhile
>> pattern or API..
>
> I hope you don't think this recasting, is in any way less confusing to a
> beginner than an inline assignment. This is language abuse!

I didn't make any claims that it wouldn't be confusing (especially as
is). It was just an _idea_. I mentioned it because (1) it uses current
syntax, (2) it doesn't require intermediate assignments or extra
indents in the main body of code, (3) it doesn't even require choosing
intermediate names, and (4) I didn't see it mentioned in any of the
previous discussion. All three of the first points have been major
sources of discussion in the thread. So I thought it might be of
interest.

> In any case, what advantages would it have over simply declaring "stashed"
> as a global inside the function and omitting the confusing subscripting?

Right. Like I said, there are many variations. I just listed one to
convey the general idea.

--Chris
___
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: Assignment Expressions

2018-05-01 Thread Steve Holden
On Tue, May 1, 2018 at 3:36 AM, Chris Jerdonek 
wrote:

> On Thu, Apr 26, 2018 at 10:33 AM, Sven R. Kunze  wrote:
> > On 25.04.2018 01:19, Steven D'Aprano wrote:
> >>
> >> Sorry, gcd(diff, n) is not the "perfect name", and I will tell you that
> >> sometimes g is better. [...]
> >
> > We were talking about the real-world code snippet of Tim (as a
> justification
> > of := ) and alternative rewritings of it without resorting to new syntax.
>
> Apologies if this idea has already been discussed (I might have missed
> the relevant email), but thinking back to Tim's earlier example--
>
> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
> return g
>
> it occurs to me this could be implemented with current syntax using a
> pattern like the following:
>
> stashed = [None]
>
> def stash(x):
> stashed[0] = x
> return x
>
> if stash(x - x_base) and stash(gcd(stashed[0], n)) > 1:
> return stashed[0]
>
> There are many variations to this idea, obviously. For example, one
> could allow passing a "name" to stash(), or combine stash / stashed
> into a single, callable object that allows setting and reading from
> its store. I wonder if one of them could be made into a worthwhile
> pattern or API..
> ​.
>

​I hope you don't think this recasting, is in any way less confusing to a
beginner than an inline assignment. This is language abuse!

In any case, what advantages would it have over simply declaring "stashed"
as a global inside the function and omitting the confusing subscripting?

regards
 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: Assignment Expressions

2018-05-01 Thread Steven D'Aprano
On Tue, May 01, 2018 at 11:04:55AM +1000, Chris Angelico wrote:

> To be fair, I don't see many people replacing "x = 1" with "for x in
> [1]: pass". Even though it IS going to have the same effect. :-)

Aside from the pass, that is precisely one of the current work-arounds 
for lack of binding-expressions inside comprehensions:

# inefficient, and wrong when f(x) has side-effects
[f(x) for x in iterable if f(x) > 1]

# what we'd like
[y for x in iterable if (y := f(x)) > 1]

# a work-around
[y for x in iterable for y in [f(x)] if y > 1]


I think that's even in your PEP, isn't it?



-- 
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: Assignment Expressions

2018-04-30 Thread Greg Ewing

Steven D'Aprano wrote:
"Not sure"? Given that you listed seven ways, how much more evidence do 
you need to conclude that it is simply wrong to say that Python has a 
single way to assign a value to a name?


Yes, but six of those are very specialised, and there's rarely
any doubt about when it's appropriate to use them.

The proposed :=, on the other hand, would overlap a lot with
the functionality of =. It's not a case of "Python already
has seven ways of assigning, so one more can't hurt."

--
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] PEP 572: Assignment Expressions

2018-04-30 Thread Chris Jerdonek
On Thu, Apr 26, 2018 at 10:33 AM, Sven R. Kunze  wrote:
> On 25.04.2018 01:19, Steven D'Aprano wrote:
>>
>> Sorry, gcd(diff, n) is not the "perfect name", and I will tell you that
>> sometimes g is better. [...]
>
> We were talking about the real-world code snippet of Tim (as a justification
> of := ) and alternative rewritings of it without resorting to new syntax.

Apologies if this idea has already been discussed (I might have missed
the relevant email), but thinking back to Tim's earlier example--

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

it occurs to me this could be implemented with current syntax using a
pattern like the following:

stashed = [None]

def stash(x):
stashed[0] = x
return x

if stash(x - x_base) and stash(gcd(stashed[0], n)) > 1:
return stashed[0]

There are many variations to this idea, obviously. For example, one
could allow passing a "name" to stash(), or combine stash / stashed
into a single, callable object that allows setting and reading from
its store. I wonder if one of them could be made into a worthwhile
pattern or API..

--Chris
___
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: Assignment Expressions

2018-04-30 Thread Steven D'Aprano
On Mon, Apr 30, 2018 at 05:27:08PM -0700, Larry Hastings wrote:
> 
> On 04/30/2018 07:30 AM, Mark Shannon wrote:
> >Would Python be better with two subtly different assignment operators?
> >The answer of "no" seems self evident to me.
> 
> Maybe this has been covered in the thread earlier--if so, I missed it, 
> sorry.  But ISTM that Python already has multiple ways to perform an 
> assignment.
> 
> All these statements assign to x:
[snip SEVEN distinct binding operations]

> I remain -1 on 572, but I'm not sure it can genuinely be said that 
> Python only has one way to assign a value to a variable.

"Not sure"? Given that you listed seven ways, how much more evidence do 
you need to conclude that it is simply wrong to say that Python has a 
single way to assign a value to a name?

:-)


-- 
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: Assignment Expressions

2018-04-30 Thread Larry Hastings


On 04/30/2018 07:30 AM, Mark Shannon wrote:

Would Python be better with two subtly different assignment operators?
The answer of "no" seems self evident to me.


Maybe this has been covered in the thread earlier--if so, I missed it, 
sorry.  But ISTM that Python already has multiple ways to perform an 
assignment.


All these statements assign to x:

   x = y
   for x in y:
   with y as x:
   except Exception as x:

And, if you want to get *super* pedantic:

   import x
   def x(): ...
   class x: ...

I remain -1 on 572, but I'm not sure it can genuinely be said that 
Python only has one way to assign a value to a variable.



//arry/
___
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: Assignment Expressions

2018-04-30 Thread Yury Selivanov
On Mon, Apr 30, 2018 at 1:03 PM Chris Angelico  wrote:
> > That's a weird argument, Chris :-)
> >
> > If `f(x)` has no meaningful name, then *what* is the result of the
> > comprehension?  Perhaps some meaningless data? ;)

> f(x) might have side effects. Can you give a meaningful name to the
> trivial helper function?

I don't understand your question. How is `f(x)` having side effects or not
having them is relevant to the discussion? Does ':=' work only with pure
functions?

> Not every trivial helper can actually have a
> name that saves people from having to read the body of the function.

I don't understand this argument either, sorry.

> >> We've been over this argument plenty, and I'm not going to rehash it.
> >
> > Hand-waving the question the way you do simply alienates more core devs
to
> > the PEP.  And PEP 572 hand-waves a lot of questions and concerns.
Asking
> > people to dig for answers in 700+ emails about the PEP is a bit too
much,
> > don't you agree?
> >
> > I think it's PEP's author responsibility to address questions right in
> > their PEP.

> If I answer every question, I make that number into 800+, then 900+,
> then 1000+. If I don't, I'm alienating everyone by being dismissive.
> If every question is answered in the PEP, the document itself becomes
> so long that nobody reads it. Damned if I do, damned if I don't. Got
> any alternative suggestions?

IMO, big part of why that we have 100s of emails is because people are very
concerned with readability.  The PEP just hand-waives the question
entirely, instead of listing good and realistic examples of code, as well
as listing bad examples.  So that, you know, people could compare them and
understand *both* pros and cons.

Instead we have a few very questionable examples in the PEP that most
people don't like at all. Moreover, half of the PEP is devoted to fixing
comprehensions scoping, which is almost an orthogonal problem to adding a
new syntax.

So my suggestion remains to continue working on the PEP, improving it and
making it more comprehensive. You're free to ignore this advice, but don't
be surprised that you see new emails about what ':=' does to code
readability (with the same arguments).  PEP 572 proponents answering to
every email with the same dismissive template doesn't help either.

> >> > def do_things(fire_missiles=False, plant_flowers=False): ...
> >> > do_things(plant_flowers:=True) # whoops!
> >
> >> If you want your API to be keyword-only, make it keyword-only. If you
> >
> > Another hand-waving.  Should we deprecate passing arguments by name if
> > their corresponding parameters are not keyword-only?
> >
> > Mark shows another potential confusion between '=' and ':=' that people
> > will have, and it's an interesting one.

> A very rare one compared to the confusions that we already have with
> '=' and '=='. And this is another argument that we've been over,
> multiple times.

How do you know if it's rare or not?  '=' is used to assign, ':=' is used
to assign, '==' is used to compare.  I can easily imagine people being
confused why '=' works for setting an argument, and why ':=' doesn't.
Let's agree to disagree on this one :)

> > Strange. I see people who struggle to format their code properly or use
the
> > language properly *every day* ;)

> And do they blame the language for having a comparison operator that
> is so easy to type? Or do they fix their bugs and move on? Again,
> language syntax is not the solution to bugs.

I'm not sure how to correlate what I was saying with your reply, sorry.

Anyways, Chris, I think that the PEP hand-waves a lot of questions and
doesn't have a comprehensive analysis of how the PEP will affect syntax and
readability. It's up to you to consider taking my advice or not. I'll try
to (again) restrain myself posting about this topic.

Y
___
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: Assignment Expressions

2018-04-30 Thread Chris Angelico
On Tue, May 1, 2018 at 2:53 AM, Yury Selivanov  wrote:
> On Mon, Apr 30, 2018 at 11:32 AM Chris Angelico  wrote:
>
>> On Tue, May 1, 2018 at 12:30 AM, Mark Shannon  wrote:
>> > List comprehensions
>> > ---
>> > The PEP uses the term "simplifying" when it really means "shortening".
>> > One example is
>> > stuff = [[y := f(x), x/y] for x in range(5)]
>> > as a simplification of
>> > stuff = [(lambda y: [y,x/y])(f(x)) for x in range(5)]
>
>> Now try to craft the equivalent that captures the condition in an if:
>
>> results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]
>
> Easy:
>
>results = []
>for x in input_data:
>   y = f(x)
>   if y > 0:
> results.append((x, y, x/y))
>
> Longer, but way more readable and debuggable if you're into that.  This has
> worked for us many years and only a handful of people complained about
> this.
>
> OTOH, I see plenty of people complaining that nested list comprehensions
> are hard to read.  In my own code reviews I ask people to avoid using
> complex comprehensions all the time.
>
>> Do that one with a lambda function.
>
> Why would I?  Is using lambda functions mandatory?

The claim was that assignment expressions were nothing more than a
shorthand for lambda functions. You can't rewrite my example with a
lambda function, ergo assignment expressions are not a shorthand for
lambda functions.

Do you agree?

>> > IMO, the "simplest" form of the above is the named helper function.
>> >
>> > def meaningful_name(x):
>> > t = f(x)
>> > return t, x/t
>> >
>> > [meaningful_name(i) for i in range(5)]
>> >
>> > Is longer, but much simpler to understand.
>
>> Okay, but what if there is no meaningful name? It's easy to say "pick
>> a meaningful name". It's much harder to come up with an actual name
>> that is sufficiently meaningful that a reader need not go look at the
>> definition of the function.
>
> That's a weird argument, Chris :-)
>
> If `f(x)` has no meaningful name, then *what* is the result of the
> comprehension?  Perhaps some meaningless data? ;)

f(x) might have side effects. Can you give a meaningful name to the
trivial helper function? Not every trivial helper can actually have a
name that saves people from having to read the body of the function.

>> > I am also concerned that the ability to put assignments anywhere
>> > allows weirdnesses like these:
>> >
>> > try:
>> > ...
>> > except (x := Exception) as x:
>> > ...
>> >
>> > with (x: = open(...)) as x:
>> > ...
>
>> We've been over this argument plenty, and I'm not going to rehash it.
>
> Hand-waving the question the way you do simply alienates more core devs to
> the PEP.  And PEP 572 hand-waves a lot of questions and concerns.  Asking
> people to dig for answers in 700+ emails about the PEP is a bit too much,
> don't you agree?
>
> I think it's PEP's author responsibility to address questions right in
> their PEP.

If I answer every question, I make that number into 800+, then 900+,
then 1000+. If I don't, I'm alienating everyone by being dismissive.
If every question is answered in the PEP, the document itself becomes
so long that nobody reads it. Damned if I do, damned if I don't. Got
any alternative suggestions?

>> > def do_things(fire_missiles=False, plant_flowers=False): ...
>> > do_things(plant_flowers:=True) # whoops!
>
>> If you want your API to be keyword-only, make it keyword-only. If you
>
> Another hand-waving.  Should we deprecate passing arguments by name if
> their corresponding parameters are not keyword-only?
>
> Mark shows another potential confusion between '=' and ':=' that people
> will have, and it's an interesting one.

A very rare one compared to the confusions that we already have with
'=' and '=='. And this is another argument that we've been over,
multiple times.

>> want a linter that recognizes unused variables, get a linter that
>> recognizes unused variables.
>
> Many want Python to be readable and writeable without linters.

And it will be. But there are going to be certain types of bug that
you won't catch as quickly. You can't use language syntax to catch
every bug. That's provably impossible.

>> Neither of these is the fault of the
>> proposed syntax; you could just as easily write this:
>
>> do_things(plant_flowers==True)
>
>> but we don't see myriad reports of people typing too many characters
>> and blaming the language.
>
> Strange. I see people who struggle to format their code properly or use the
> language properly *every day* ;)

And do they blame the language for having a comparison operator that
is so easy to type? Or do they fix their bugs and move on? Again,
language syntax is not the solution to bugs.

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: Assignment Expressions

2018-04-30 Thread Yury Selivanov
On Mon, Apr 30, 2018 at 11:32 AM Chris Angelico  wrote:

> On Tue, May 1, 2018 at 12:30 AM, Mark Shannon  wrote:
> > List comprehensions
> > ---
> > The PEP uses the term "simplifying" when it really means "shortening".
> > One example is
> > stuff = [[y := f(x), x/y] for x in range(5)]
> > as a simplification of
> > stuff = [(lambda y: [y,x/y])(f(x)) for x in range(5)]

> Now try to craft the equivalent that captures the condition in an if:

> results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]

Easy:

   results = []
   for x in input_data:
  y = f(x)
  if y > 0:
results.append((x, y, x/y))

Longer, but way more readable and debuggable if you're into that.  This has
worked for us many years and only a handful of people complained about
this.

OTOH, I see plenty of people complaining that nested list comprehensions
are hard to read.  In my own code reviews I ask people to avoid using
complex comprehensions all the time.

> Do that one with a lambda function.

Why would I?  Is using lambda functions mandatory?


> > IMO, the "simplest" form of the above is the named helper function.
> >
> > def meaningful_name(x):
> > t = f(x)
> > return t, x/t
> >
> > [meaningful_name(i) for i in range(5)]
> >
> > Is longer, but much simpler to understand.

> Okay, but what if there is no meaningful name? It's easy to say "pick
> a meaningful name". It's much harder to come up with an actual name
> that is sufficiently meaningful that a reader need not go look at the
> definition of the function.

That's a weird argument, Chris :-)

If `f(x)` has no meaningful name, then *what* is the result of the
comprehension?  Perhaps some meaningless data? ;)


> > I am also concerned that the ability to put assignments anywhere
> > allows weirdnesses like these:
> >
> > try:
> > ...
> > except (x := Exception) as x:
> > ...
> >
> > with (x: = open(...)) as x:
> > ...

> We've been over this argument plenty, and I'm not going to rehash it.

Hand-waving the question the way you do simply alienates more core devs to
the PEP.  And PEP 572 hand-waves a lot of questions and concerns.  Asking
people to dig for answers in 700+ emails about the PEP is a bit too much,
don't you agree?

I think it's PEP's author responsibility to address questions right in
their PEP.


> > def do_things(fire_missiles=False, plant_flowers=False): ...
> > do_things(plant_flowers:=True) # whoops!

> If you want your API to be keyword-only, make it keyword-only. If you

Another hand-waving.  Should we deprecate passing arguments by name if
their corresponding parameters are not keyword-only?

Mark shows another potential confusion between '=' and ':=' that people
will have, and it's an interesting one.

> want a linter that recognizes unused variables, get a linter that
> recognizes unused variables.

Many want Python to be readable and writeable without linters.

> Neither of these is the fault of the
> proposed syntax; you could just as easily write this:

> do_things(plant_flowers==True)

> but we don't see myriad reports of people typing too many characters
> and blaming the language.

Strange. I see people who struggle to format their code properly or use the
language properly *every day* ;)

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] PEP 572: Assignment Expressions

2018-04-30 Thread Antoine Pitrou

Le 30/04/2018 à 17:30, Chris Angelico a écrit :



def do_things(fire_missiles=False, plant_flowers=False): ...
do_things(plant_flowers:=True) # whoops!


If you want your API to be keyword-only, make it keyword-only. If you
want a linter that recognizes unused variables, get a linter that
recognizes unused variables. Neither of these is the fault of the
proposed syntax; you could just as easily write this:

do_things(plant_flowers==True)


Unless you have a `plant_flowers` variable already defined, this will 
raise a NameError, not plant a silent bug.


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] PEP 572: Assignment Expressions

2018-04-30 Thread Chris Angelico
On Tue, May 1, 2018 at 12:30 AM, Mark Shannon  wrote:
> List comprehensions
> ---
> The PEP uses the term "simplifying" when it really means "shortening".
> One example is
> stuff = [[y := f(x), x/y] for x in range(5)]
> as a simplification of
> stuff = [(lambda y: [y,x/y])(f(x)) for x in range(5)]

Now try to craft the equivalent that captures the condition in an if:

results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]

Do that one with a lambda function.

> IMO, the "simplest" form of the above is the named helper function.
>
> def meaningful_name(x):
> t = f(x)
> return t, x/t
>
> [meaningful_name(i) for i in range(5)]
>
> Is longer, but much simpler to understand.

Okay, but what if there is no meaningful name? It's easy to say "pick
a meaningful name". It's much harder to come up with an actual name
that is sufficiently meaningful that a reader need not go look at the
definition of the function.

> I am also concerned that the ability to put assignments anywhere
> allows weirdnesses like these:
>
> try:
> ...
> except (x := Exception) as x:
> ...
>
> with (x: = open(...)) as x:
> ...

We've been over this argument plenty, and I'm not going to rehash it.

> def do_things(fire_missiles=False, plant_flowers=False): ...
> do_things(plant_flowers:=True) # whoops!

If you want your API to be keyword-only, make it keyword-only. If you
want a linter that recognizes unused variables, get a linter that
recognizes unused variables. Neither of these is the fault of the
proposed syntax; you could just as easily write this:

do_things(plant_flowers==True)

but we don't see myriad reports of people typing too many characters
and blaming the language.

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: Assignment Expressions

2018-04-30 Thread Mark Shannon

Hi,

On 17/04/18 08:46, Chris Angelico wrote:

Having survived four rounds in the boxing ring at python-ideas, PEP
572 is now ready to enter the arena of python-dev. 


I'm very strongly opposed to this PEP.

Would Python be better with two subtly different assignment operators?
The answer of "no" seems self evident to me.

Do we need an assignment expression at all (regardless of the chosen 
operator)? I think we do not.

Assignment is clear at the moment largely because of the context;
it can only occur at the statement level.
Consequently, assignment and keyword arguments are never confused
despite have the same form `name = expr`

List comprehensions
---
The PEP uses the term "simplifying" when it really means "shortening".
One example is
stuff = [[y := f(x), x/y] for x in range(5)]
as a simplification of
stuff = [(lambda y: [y,x/y])(f(x)) for x in range(5)]

IMO, the "simplest" form of the above is the named helper function.

def meaningful_name(x):
t = f(x)
return t, x/t

[meaningful_name(i) for i in range(5)]

Is longer, but much simpler to understand.



I am also concerned that the ability to put assignments anywhere
allows weirdnesses like these:

try:
...
except (x := Exception) as x:
...

with (x: = open(...)) as x:
...

def do_things(fire_missiles=False, plant_flowers=False): ...
do_things(plant_flowers:=True) # whoops!


It is easy to say "don't do that", but why allow it in the first place?

Cheers,
Mark.
___
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: Assignment Expressions

2018-04-26 Thread Chris Angelico
On Fri, Apr 27, 2018 at 3:33 AM, Sven R. Kunze  wrote:
> On 25.04.2018 01:19, Steven D'Aprano wrote:
>>
>> Sorry, gcd(diff, n) is not the "perfect name", and I will tell you that
>> sometimes g is better. [...]
>
>
> We were talking about the real-world code snippet of Tim (as a justification
> of := ) and alternative rewritings of it without resorting to new syntax.
> Not about "sometimes", or in some toy examples, or code without unknown
> life-time and intention (interactive, library, etc).

You're asking for some massive changes in semantics, though. If you
want to discuss that, it's nothing at all to do with PEP 572, and is a
completely new proposal.

>> You might know that, but how does somebody reading the code know
>> which functions are pure and which are not? How does the compiler know?
>
>
> There are invisible optimizations in CPython already.
> And for the most obvious examples, humans don't need to know. It's like
> wondering if constant folding really works.
> It's the same with all optimizations: if it works, it's fine. If it cannot
> be made working, the original code still works and you can optimize by hand
> anyway.
> The two obvious ways: the compiler might have a predefined list of pure
> functions OR the code tells him with an annotation of any sort.
> Both ways work, the latter somehow feels cleaner.

An annotation? You mean like functools.lru_cache? That's technically
nothing to do with pure functions, but it's about as much as you're
likely to get. The function still has to be called, and the result has
to be cached somewhere. Ultimately, "pure function optimization" is
just another form of cache.

Please, take this to python-ideas, or even better, to python-list.
It's not a counter-argument to PEP 572.

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: Assignment Expressions

2018-04-26 Thread Sven R. Kunze

On 25.04.2018 01:19, Steven D'Aprano wrote:

Sorry, gcd(diff, n) is not the "perfect name", and I will tell you that
sometimes g is better. [...]


We were talking about the real-world code snippet of Tim (as a 
justification of := ) and alternative rewritings of it without resorting 
to new syntax.
Not about "sometimes", or in some toy examples, or code without unknown 
life-time and intention (interactive, library, etc).



You might know that, but how does somebody reading the code know
which functions are pure and which are not? How does the compiler know?


There are invisible optimizations in CPython already.
And for the most obvious examples, humans don't need to know. It's like 
wondering if constant folding really works.
It's the same with all optimizations: if it works, it's fine. If it 
cannot be made working, the original code still works and you can 
optimize by hand anyway.
The two obvious ways: the compiler might have a predefined list of pure 
functions OR the code tells him with an annotation of any sort.

Both ways work, the latter somehow feels cleaner.


It's easy to say that you recognise gcd as a pure function. How about
len(document.chapter[this_chapter].pages()), is that a pure function?


What exactly do you want me to answer? An algorithm? A trained neural 
network?
Usually, one starts with the low-hanging fruits and extends if possible 
and needed.

So that would be way out of scope.
___
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: Assignment Expressions

2018-04-25 Thread David Shawley
On Apr 24, 2018, at 2:10 PM, MRAB  wrote:
> 
> On 2018-04-21 03:15, Tim Peters wrote:
>> [Tim]
>> >> And I'll take this opportunity to repeat the key point for me:  I
>> >> tried hard, but never found a single case based on staring at real
>> >> code where allowing _fancier_ (than "plain name") targets would be a
>> >> real improvement.  In every case I thought it _might_ help, it turned
>> >> out that it really didn't unless Python _also_ grew an analog to C's
>> >> "comma operator" (take only the last result from a sequence of
>> >> expressions).  I'll also note that I asked if anyone else had a
>> >> real-life example, and got no responses.
>> 
>> [MRAB ]
>> > Could a semicolon in a parenthesised expression be an equivalent to C's
>> > "comma operator"?
>> 
>> I expect it could, but I it's been many years since I tried hacking
>> Python's grammar, and I wouldn't want a comma operator anyway ;-)
> [snip]
> Just reading this:
> 
> https://www.bfilipek.com/2018/04/refactoring-with-c17-stdoptional.html
> 
> about C++17, and what did I see? An example with a semicolon in parentheses!

A similar pattern shows up in Go's if statement syntax.  It is interesting to 
note that it is part of the grammar specifically for the if statement and *not* 
general expression syntax.

IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block 
) ] .

Bindings that occur inside of `SimpleStmt` are only available within the 
`Expression` and blocks that make up the if statement.

https://golang.org/ref/spec#If_statements

This isn't a good reason to parrot the syntax in Python though.  IMO, I 
consider the pattern to be one of the distinguishing features of golang and 
would be happy leaving it there.

I have often wondered if adding the venerable for loop syntax from C (and many 
other languages) would solve some of the needs here though.  The for loop 
syntax in golang is interesting in that it serves as both a standard multipart 
for statement as well as a while statement.

Changing something like this is more of a Python 4 feature and I think that I 
would be -0 on the concept.  I did want to mention the similarities for the 
posterity though.

ChrisA - we might want to add explicit mentions of golang's if statement and 
for loop as "considered" syntaxes since they are in a sibling programing 
language (e.g., similar to async/await in PEP 492).

- dave
--
"Syntactic sugar causes cancer of the semicolon" - Alan Perlis___
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: Assignment Expressions

2018-04-25 Thread Steve Holden
On Wed, Apr 25, 2018 at 6:15 AM, Nick Coghlan  wrote:

> On 25 April 2018 at 13:56, Guido van Rossum  wrote:
> > On Tue, Apr 24, 2018 at 8:24 PM, Nick Coghlan 
> wrote:
> >>
> >> I also think it would be good for the PEP to spell out the following
> >> semantic invariant for code running in a regular namespace:
> >>
> >> _rhs = expr
> >> assert (target := _rhs) is _rhs and target is _rhs
> >>
> >> It's the restriction to single names as targets that makes it possible
> >> to impose such a strong assertion about what the syntax means.
> >
> > Can you elaborate? I don't understand what you mean by this.
>
> The assertion is just spelling out in code form that given the name
> binding expression "target := expr", then:
>
> 1. the result of the expression itself is "expr", exactly as if the
> name binding was omitted
> 2. that result is also bound to the name "target" in the current scope
>
> The preceding "_rhs = expr" line is included to make the invariant
> generalise even to expressions that have side effects or can change
> their output based on mutable system state.
>
> Ironically, that may be clearer if I use another assignment statement
> to break it out as two separate invariants:
>
> _rhs = expr
> _inline_result = (bound_name := _rhs)
> assert _inline_result is _rhs
> assert bound_name is _rhs
>
> By contrast, the protocols involved in handling more complex
> assignment targets and in handling augmented assignment mean that it
> wouldn't be possible to define a similarly simple invariant of what
> they mean (since the exact runtime behaviour would be both type and
> target dependent).
>
>
​While it's handy that one _could_ use any valid assignment target,
allowing this wouldn't (IMHO) necessarily be a good idea.
Binding/assignment expressions fit well into Python's semantics (where
bindings copy references rather than data) precisely because names are
effectively and straightforwardly shorthand for values at the point of
assignment.

Restricting the targets in

target := expression

to simple names would avoid a lot of the tricksiness that less experienced
programmers might be tempter to indulge, leading to simpler code without
undue restrictions on what can be done.

The PEP is currently somewhat confused on naming, since it is entitled
"Assignment Expressions" but appears to then exclusively use the name
"named expressions" to reference the concept under "Syntax and Semantics"
and "assignment expression" elsewhere. I'd prefer the term "name binding
expressions," since that implies the stricture that more complex targets
are excluded. Whatever is chosen, usage in the PEP should be consistent.

regards
 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: Assignment Expressions

2018-04-24 Thread Nick Coghlan
On 25 April 2018 at 13:56, Guido van Rossum  wrote:
> On Tue, Apr 24, 2018 at 8:24 PM, Nick Coghlan  wrote:
>>
>> I also think it would be good for the PEP to spell out the following
>> semantic invariant for code running in a regular namespace:
>>
>> _rhs = expr
>> assert (target := _rhs) is _rhs and target is _rhs
>>
>> It's the restriction to single names as targets that makes it possible
>> to impose such a strong assertion about what the syntax means.
>
> Can you elaborate? I don't understand what you mean by this.

The assertion is just spelling out in code form that given the name
binding expression "target := expr", then:

1. the result of the expression itself is "expr", exactly as if the
name binding was omitted
2. that result is also bound to the name "target" in the current scope

The preceding "_rhs = expr" line is included to make the invariant
generalise even to expressions that have side effects or can change
their output based on mutable system state.

Ironically, that may be clearer if I use another assignment statement
to break it out as two separate invariants:

_rhs = expr
_inline_result = (bound_name := _rhs)
assert _inline_result is _rhs
assert bound_name is _rhs

By contrast, the protocols involved in handling more complex
assignment targets and in handling augmented assignment mean that it
wouldn't be possible to define a similarly simple invariant of what
they mean (since the exact runtime behaviour would be both type and
target dependent).

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: Assignment Expressions

2018-04-24 Thread Guido van Rossum
On Tue, Apr 24, 2018 at 8:24 PM, Nick Coghlan  wrote:

> I also think it would be good for the PEP to spell out the following
> semantic invariant for code running in a regular namespace:
>
> _rhs = expr
> assert (target := _rhs) is _rhs and target is _rhs
>
> It's the restriction to single names as targets that makes it possible
> to impose such a strong assertion about what the syntax means.
>

Can you elaborate? I don't understand what you mean by this.

-- 
--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] PEP 572: Assignment Expressions

2018-04-24 Thread Nick Coghlan
On 25 April 2018 at 06:23, Mike Miller  wrote:
> Now, I agree that's not a difference of much consequence, but the difference
> from "import as" is not either.

Since this example has been brought up by a few folks now, I'll note
that "import x.y.z as c" has never been entirely equivalent to a
simple assignment, since it *also* avoids the default binding of "x"
in the current namespace.

These days, it's diverged even further, since we added a fallback to
looking for the full "x.y.z" key in sys.modules if any part of the
submodule lookup chain gets an AttributeError.

The proposed name binding expressions aren't like that - they really
are just an ordinary binding of the result of the given expression to
the given name.

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: Assignment Expressions

2018-04-24 Thread Nick Coghlan
On 25 April 2018 at 03:01, Tim Peters  wrote:
> assignment statement buried deep inside expressions.  But in
> conventional use, "binding" is restricted to identifiers, which vastly
> simplifies the mental model for "the worst" that can happen.

[snip]

> But, in the absence of Guido chiming in, it's really up to you.  A few
> people have expressed positive feelings about changing the name to
> "binding expressions", and none opposed it (that I saw), but the
> sample size is too small to claim that "proves" anything.

I go back and forth, as I suspect even if we call them "name binding
expressions" in the language reference (which I think would be a good
idea), they'll often be referred to colloquially as "assignment
expressions". That's probably OK though - list displays and dict
displays are regularly referred to as literals, and the meaning
remains clear, even though the use of literal is technically
inaccurate.

I also think it would be good for the PEP to spell out the following
semantic invariant for code running in a regular namespace:

_rhs = expr
assert (target := _rhs) is _rhs and target is _rhs

It's the restriction to single names as targets that makes it possible
to impose such a strong assertion about what the syntax means.

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: Assignment Expressions

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 10:42:35PM +0200, Sven R. Kunze wrote:

> gcd(diff, n) is to me a perfect name, and please don't tell me g is 
> better. ;)

Sorry, gcd(diff, n) is not the "perfect name", and I will tell you that 
sometimes g is better.

Which would you prefer to see and read?

g = gcd(diff, n)
result = [g, g+2, 3*g, g**5]

or:

result = [gcd(diff, n), gcd(diff, n)+2, 3*gcd(diff, n), gcd(diff, n)**5]

Forget about the inefficiency of calculating the same result over and 
over again. Just think about reading the code, especially aloud. If you 
were describing the code to a colleague, would you really repeat the 
phrase "gcd of diff, n" *four* separate times? I don't know about you, 
but I wouldn't, and I wouldn't want to read it four separate times.

Think about having to edit it. Would you rather edit it in one place or 
four? Even close together, in a single expression, it is annoying to 
have "gcd(diff, n)" repeated over and over again.


> To me it seems, that many people consider function_of_parameter a better 
> name than function(parameter). IMO it isn't.

Of course not. But in some contexts, p is a much better name than 
function(parameter). In other contexts, something more descriptive will 
be a better name:

page_count = (len(document.chapter[previous_chapter].pages()) 
  + len(document.chapter[this_chapter].pages()))

page_count is a MUCH better name than repeating 

(len(document.chapter[previous_chapter].pages())
 + len(document.chapter[this_chapter].pages()))

over and over again, even if it is a pure function.



> I've seen lots of code where people do things like foo_of_bar = 
> bar['foo']. Because they don't want another dict access, or they think 
> it better reflects the concept. But it does not as does not g. Writing 
> gcd(diff, n) twice is not more repeating as is writing foo_of_bar twice. 
> Because gcd is a pure function

You might know that, but how does somebody reading the code know 
which functions are pure and which are not? How does the compiler know?

It's easy to say that you recognise gcd as a pure function. How about 
len(document.chapter[this_chapter].pages()), is that a pure function?



-- 
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: Assignment Expressions

2018-04-24 Thread Sven R. Kunze

On 23.04.2018 23:41, Tim Peters wrote:

Why?  "Give the result of an expression a name" is already heavily
used in Python - it's just that the _contexts_ in which it can be done
are very limited now.


Which is a good thing IMO. It keeps stuff simple to reason about.
At least to me, the objective of an expression is to generate a
result, not to introduce new names. YMMV.


After decades, CPython still does nothing of the sort, short of having
eventually made, e.g., "None" and "True" and "False" reserved words so
at least it can optimize uses of those.  It knows nothing at all about
which library functions are pure - and there's no code in the
implementation currently capable of exploiting such information even
if it were known.  That remains a fantasy in CPython.


CPython optimizes on dicts pretty heavily and on a lot of other things 
as well.
Victor, e.g., is pretty prolific here when it comes to optimizing things 
for the 95% usecases.

Maybe, considering pure functions might be another step.


Guido gave better ones, where binding expressions would allow to
collapse arbitrarily deep levels of nesting to just one (if ... elif
... elif ... elif ...). My example only eliminated a single level of
artificial indentation.  But my example did have the advantage of
being taken verbatim from actual, working code ;-)


I like the example, but not the solution it proposes.

gcd(diff, n) is to me a perfect name, and please don't tell me g is 
better. ;)
To me it seems, that many people consider function_of_parameter a better 
name than function(parameter). IMO it isn't.
I've seen lots of code where people do things like foo_of_bar = 
bar['foo']. Because they don't want another dict access, or they think 
it better reflects the concept. But it does not as does not g. Writing 
gcd(diff, n) twice is not more repeating as is writing foo_of_bar twice. 
Because gcd is a pure function, gcd(diff, n) is just a synonym/name of 
the very same number. That it needs to be calced twice, is a detail, 
like a double dict access.


In the end, it's only optimizing what could a be done by a machine much 
more reliably.
Though, people now want to save that extra assignment line (and 
indentations) via syntax,
because they do that kind of optimizing and want to do it by hand for 
some reason.


Just my 2 cents to let you see where I'm coming from.


___
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: Assignment Expressions

2018-04-24 Thread Mike Miller


On 2018-04-24 12:59, Chris Angelico wrote:

Aside from the restriction to binding only to a simple name, and the
fact that they're also an expression with the same value, how are they
not the same as plain assignment? Any discrepancies should be
considered bugs.


Slightly different in that they return the value, and are expressions not 
assignment statements.


Now, I agree that's not a difference of much consequence, but the difference 
from "import as" is not either.


-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] PEP 572: Assignment Expressions

2018-04-24 Thread Mike Miller


On 2018-04-23 14:19, Barry Warsaw wrote:

Me too.  Plus we *already* have precedence for spelling name bindings in 
similar constructs, such as import statements, with statements, and exceptions. 
 It seems like a natural and Pythonic approach to extend that same spelling to 
binding expressions rather than introducing new, weird, symbols.


We've survived for decades without this syntax, so don't think the need is so 
great that we need to rush it.  Let's not "jump the shark."  :D


In my opinion, "EXPR as NAME" is the only version worthy enough for the 
readability of Python.  It reads like psuedo-code, as advocates have described 
in the past, and already used frequently in a fuzzy, non-dogmatic manner.


The point about the potential of a bug in the "with" statement is worth serious 
consideration however.  I don't have a problem with it, but if deemed 
intolerable there was an additional solution I read upthread, believe by Kirill 
and Steve.


Merely that, since all current use cases are in the if/while/comprehension 
statements, it might be a good idea to limit binding-expressions there to avoid 
issues/overuse elsewhere.


Well, there are a number of mitigations to the "with" issue that could be 
considered.


(Hoping that this is my last post on the subject.)

-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] PEP 572: Assignment Expressions

2018-04-24 Thread Ethan Furman

On 04/24/2018 12:59 PM, Chris Angelico wrote:

On Wed, Apr 25, 2018 at 5:54 AM, Mike Miller wrote:



Also, these "binding expressions" are not exactly plain assignment, as it
has been known.


Aside from the restriction to binding only to a simple name, and the
fact that they're also an expression with the same value, how are they
not the same as plain assignment? Any discrepancies should be
considered bugs.


They only bind to simple names, and they can occur in expressions.  ;)

--
~Ethan~

___
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: Assignment Expressions

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 5:54 AM, Mike Miller  wrote:
> Also, these "binding expressions" are not exactly plain assignment, as it
> has been known.

Aside from the restriction to binding only to a simple name, and the
fact that they're also an expression with the same value, how are they
not the same as plain assignment? Any discrepancies should be
considered bugs.

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: Assignment Expressions

2018-04-24 Thread Mike Miller


On 2018-04-23 15:36, Guido van Rossum wrote:
- the semantics are subtly different from all other uses of 'as' in Python; I'd 
like to reserve 'as' for "not a plain assignment"


It's conceptually similar to "import as", no?  The keyword "as" is a fuzzy yet 
intuitive concept already.


Also, these "binding expressions" are not exactly plain assignment, as it has 
been known.


-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] PEP 572: Assignment Expressions

2018-04-24 Thread Skip Montanaro
>
> Just reading this:
>
> https://www.bfilipek.com/2018/04/refactoring-with-c17-stdoptional.html
>
> about C++17, and what did I see? An example with a semicolon in
> parentheses!
>

Isn't that kind of the C++ motto? "Leave no syntactic stone unturned."
Whereas in Python, the syntax motto might better be stated, "We will ship
no syntax before its time." (With apologies to Ernest and Julio Gallo.)

Skip
___
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: Assignment Expressions

2018-04-24 Thread MRAB

On 2018-04-21 03:15, Tim Peters wrote:

[Tim]
>> And I'll take this opportunity to repeat the key point for me:  I
>> tried hard, but never found a single case based on staring at real
>> code where allowing _fancier_ (than "plain name") targets would be a
>> real improvement.  In every case I thought it _might_ help, it turned
>> out that it really didn't unless Python _also_ grew an analog to C's
>> "comma operator" (take only the last result from a sequence of
>> expressions).  I'll also note that I asked if anyone else had a
>> real-life example, and got no responses.

[MRAB ]
> Could a semicolon in a parenthesised expression be an equivalent to C's
> "comma operator"?

I expect it could, but I it's been many years since I tried hacking
Python's grammar, and I wouldn't want a comma operator anyway ;-)

[snip]
Just reading this:

https://www.bfilipek.com/2018/04/refactoring-with-c17-stdoptional.html

about C++17, and what did I see? An example with a semicolon in parentheses!

___
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: Assignment Expressions

2018-04-24 Thread Tim Peters
[Chris Angelico ]
> Hopefully you have seen, or soon will see, the latest posting of the
> PEP, in which assignment targets are restricted to simple names. :)

I haven't yet, but look forward to it!  You have the patience of a
saint to endure all this - I would have given up 6 years ago ;-)


> Though I still talk about "assignment expressions". I don't see a
> problem with calling them that, but I also don't see a problem with
> calling them "binding expressions" if you prefer.

It's psychology ;-)  So long as the PEP calls them assignment
expressions, people are going to imagine facing the horrors of things
like the current

*b, c = a[c] = a

assignment statement buried deep inside expressions.  But in
conventional use, "binding" is restricted to identifiers, which vastly
simplifies the mental model for "the worst" that can happen.

Since fear is the most potent motivator, "don't scare people" is rule #1 ;-)

But, in the absence of Guido chiming in, it's really up to you.  A few
people have expressed positive feelings about changing the name to
"binding expressions", and none opposed it (that I saw), but the
sample size is too small to claim that "proves" anything.
___
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: Assignment Expressions

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 2:40 AM, Tim Peters  wrote:
> [Antoine]
>> ...
>> Yes... I think most will agree that Python is generally easy to take up
>> for people coming from C++ etc., so my "easier to learn and teach" was
>> mostly about non-programmers.
>
> [Tim]
>>> even for raw beginners the semantics are the tiniest part of what
>>> they need to learn anyway about Python's assignment expressions.
>
>> I'm not sure what you mean by that.  If it's the tiniest part, what's
>> the overwhelming part?
>
> I was hoping it was clear from context that I was talking about
> "binding expressions", not the PEP's wholly general "assignment
> expressions".

Hopefully you have seen, or soon will see, the latest posting of the
PEP, in which assignment targets are restricted to simple names. :)
Though I still talk about "assignment expressions". I don't see a
problem with calling them that, but I also don't see a problem with
calling them "binding expressions" if you prefer.

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: Assignment Expressions

2018-04-24 Thread Tim Peters
[Antoine]
> ...
> Yes... I think most will agree that Python is generally easy to take up
> for people coming from C++ etc., so my "easier to learn and teach" was
> mostly about non-programmers.

[Tim]
>> even for raw beginners the semantics are the tiniest part of what
>> they need to learn anyway about Python's assignment expressions.

> I'm not sure what you mean by that.  If it's the tiniest part, what's
> the overwhelming part?

I was hoping it was clear from context that I was talking about
"binding expressions", not the PEP's wholly general "assignment
expressions".


> Is the new assigment expression that delicate to use that it requires
> reading a long and intimidating design document ? I didn't get that
> impression, so it seems you may be making a stronger point than me
> for rejecting the PEP :-)

I'm -1 myself on the PEP's assignment expressions, because there are
no compelling use cases yet for any but the simplest ("binding
expressions") cases.  And, yes, understanding Python's assignment
statements is challenging.  Just understanding their grammar is
challenging:

assignment_stmt ::=  (target_list "=")+ (starred_expression | yield_expression)
target_list ::=  target ("," target)* [","]
target  ::=  identifier
 | "(" [target_list] ")"
 | "[" [target_list] "]"
 | attributeref
 | subscription
 | slicing
 | "*" target

Followed by pages of dense text explaining what all those
possibilities mean.  A binding expression is more like:

binding_expression ::= identifier ":=" expression

and the only part of the assignment statement docs needed to explain
the meaning is the brief "If the target is an identifier (name)"
section, augmented with "and the value of `expression` is the value of
the binding expression".  If someone has learned what

i = 1

means, they already learned almost all of what binding expressions
mean too.  The target in a binding expression can't be more
complicated than the `i` in that example.


>>> "await" is a more readable and less confusing improvement
>>> over "yield from".

>> Heh.  Not to me.  I have literally have no idea what to with "await"
>> (I use generators heavily, but have had no use yet for coroutines),
>> but use
>>
>> yield from an_iterable
>>
>> routinely.

> Yeah... "yield from" is fine for that, except that it was explicitly
> meant for the coroutine use case as well (I'm not sure what the
> timeline is, but probably Guido was already thinking/dreaming about
> tulip/asyncio back then). And trying to shoehorn both in a single
> construct made it confusing and inadequate.
>
> When you want to express two abstractly different concepts (generating
> a stream of values, or suspending a task until some asynchronous subtask
> finishes), it makes things easier if those two concepts have two
> different concrete expressions. Hence "await" making the language
> easier to learn for those whose use cases benefit from it.

All of which I remain blissfully unaware of :-)


...
>> It's simply impossible that, whatever "await" does, it
>> could be more readable or less confusing than what I use "yield from"
>> for.

> Probably because "await" wouldn't work at all for you, then :-)

I'm glad people who need "await" got it - they'd have to pry _my_ uses
of "yield from" from my cold, dead fingers ;-)  Despite that all my
uses could be trivially replaced by

for _ in an_iterable:
yield _

"yield from" saves typing, indentation, and conceptual noise for me.
It's the "binding expressions" of nested generators ;-)


>>>  Format strings dispense from the older, more convoluted formulations.

>> But they didn't _replace_ them.  That made teaching/learning harder,
>> not easier,

> Intuitively, it sounds easier to teach f'some {value}' rather than
> either the .format() or %-formatting alternatives.  The whole goal of
> f-strings, after all, is to make string formatting more approachable.
>
> Learning a language is not learning the whole spec.  When you learn C,
> you don't need to learn the oddities of pre-ANSI function
> declarations :-)

A difference is that there still are mountains of code using earlier
string formatting methods, and my guess is that there always will be.
f-strings aren't always "better".  For example, any number of
generators (including the combinatoric generators from itertools)
yield a sequence of tuples, and

format_string % a_tuple

is often the simplest way to format the tuple components.  Breaking
the tuple apart first, whether via explicit indexing in an f-string,
or via unpacking into a tuple of names for use in an f-string, is
often needless complication.

So % formatting needs to be learned by anyone who wants to read
_other_ peoples' code.

Then again, that's fine by me, because I don't really care whether
something new needs to be learned.  What I do care about is whether
the benefits exceed the co

Re: [Python-Dev] PEP 572: Assignment Expressions

2018-04-24 Thread Ethan Furman

On 04/23/2018 06:42 PM, Chris Jerdonek wrote:

On Mon, Apr 23, 2018 at 4:54 PM, Greg Ewing wrote:

Tim Peters wrote:



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



My problem with this is -- how do you read such code out loud?


It could be--

"if diff, which we let equal x - x_base, and g, which ..." or
"if diff, which we set equal to x - x_base, and g, which " or
"if diff, which we define to be x - x_base, and g, which " or
"if diff, which we define as x - x_base, and g, which ." etc.


Thanks, Chris J.

For myself, I can read that as

"if diff, which is x - x_base, and g, which is ..."

That works for me.

Changing my vote to

+1  (but only for simple name bindings)

--
~Ethan~

___
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: Assignment Expressions

2018-04-24 Thread Nick Coghlan
On 24 April 2018 at 22:30, David Mertz  wrote:
> I do think the pronunciation issue that Greg notices is important.  I teach
> Python for most of my living, and reading and discussing code segments is an
> important part of that.  When focussing on how Python actually *spells*
> something, you can't always jump to the higher-level meaning of a construct.
> For some complex expression—whether or not "binding expressions" are
> added—sometimes it makes sense to give a characterization of the *meaning*
> of the expression, but other times you want to say aloud the entire spelling
> of the expression.
>
> Although feelings are mixed about this, I like the "dunder" contraction for
> this purpose.  It's less of a mouthful to say "dunder-init" than
> "underscore-underscore-init-underscore-underscore" aloud.  And once you
> learn that shorthand, it's unambiguous.
>
> I think I'd pronounce:
>
> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
> return g
>
> As:
>
> "If diff bound to x minus x_base (is non-zero), and g bound to gcd of diff
> comma n is greater than 1, return g"

Pronouncing it as "name bound to expr" would also fit well with
calling the overall construct a binding expression.

You could also postpone the definitions to the end when speaking aloud:

"if diff is true and g is greater than 1, then return g, given
that diff is bound to ex minus ex-base and g is bound to the gcd of
diff and n"

However, that long form sounded awkward to me, though, so I ended up
wanting to rephrase it as just:

"if diff is true and g is greater than 1, then return g, given
that diff is ex minus ex-base and g is the gcd of diff and n"

(The only change is to replace both occurrences of  "is bound to" with
a simple "is")

And writing that out actually gave me an idea that I don't believe has
come up before (or if it did, it got lost somewhere in the depths of a
long python-ideas thread):

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

With the mnemonic for what the binding expression means being the
following invariant:

_rhs = expr
assert (name is= _rhs) is _rhs and name is _rhs

In a very real sense, that's *exactly* recreating the C pointer
semantics for "==" ("check if two pointers reference the same object")
vs "=" ("make two pointers reference the same object"), we'd just be
spelling it as "is" vs "is=".

Given that spelling, a reasonable inline pronunciation of "is=" would
still be Davids suggestion of "is bound to":

"if diff is bound to ex minux ex-base and is true and g is bound
to the gcd of diff and n and is greater than 1, then return g"

Simplifying "is bound to" to "is" in the post-definition form would
just be a verbal shorthand.

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: Assignment Expressions

2018-04-24 Thread David Mertz
I do think the pronunciation issue that Greg notices is important.  I teach
Python for most of my living, and reading and discussing code segments is
an important part of that.  When focussing on how Python actually *spells*
something, you can't always jump to the higher-level meaning of a
construct.  For some complex expression—whether or not "binding
expressions" are added—sometimes it makes sense to give a characterization
of the *meaning* of the expression, but other times you want to say aloud
the entire spelling of the expression.

Although feelings are mixed about this, I like the "dunder" contraction for
this purpose.  It's less of a mouthful to say "dunder-init" than
"underscore-underscore-init-underscore-underscore" aloud.  And once you
learn that shorthand, it's unambiguous.

I think I'd pronounce:

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

As:

"If diff bound to x minus x_base (is non-zero), and g bound to gcd of diff
comma n is greater than 1, return g"

But having a convention for pronouncing this would be nice, rather than it
being my idiosyncrasy.


On Mon, Apr 23, 2018 at 8:23 PM, Tim Peters  wrote:

> [Tim]
> >> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
> >> return g
>
> [Greg Ewing ]
> > My problem with this is -- how do you read such code out loud?
>
> In the message in which I first gave that example:
>
> if the diff isn't 0 and gcd(diff, n) > 1, return the gcd.
>That's how I _thought_ of it from the start.
>
> In my mind, `x - x_base` doesn't even exist except as a low-level
> definition of what "diff" means.  It's different for the other test:
> _there_ `g` doesn't exist except as a shorthand for "the gcd".  In one
> case it's the name that's important to me, and in the other case the
> expression.  The entire function from which this came is doing all
> arithmetic modulo `n`, so `n` isn't in my mind either - it's a
> ubiquitous part of the background in this specific function.
>
> But you did ask how_I_ would read that code ;-)  Anyone else is free
> to read it however they like.  I naturally read it in the way that
> makes most sense to me in its context.
>
>
> > From my Pascal days I'm used to reading ":=" as "becomes". So
> > this says:
> >
> >"If diff becomes x - base and g becomes gcd(diff, n) is
> > greater than or equal to 1 then return g."
> >
> > But "diff becomes x - base" is not what we're testing!
>
> I don't really follow that.  In Python,
>
> if f() and g > 1:
>
> first tests whether `f()` "is truthy", regardless of whether it does
> or doesn't appear in a binding expression.  Because this code is
> working with integers, there's an _implied_ "!= 0" comparison.
>
>
> > That makes it sound like the result of x - base may or may not
> > get assigned to diff, which is not what's happening at all.
>
> Then I suggest the problem you're having doesn't stem from the binding
> expression, but from that you're omitting to fill in the != 0 part:
> if you're not thrown by "greater than 1", I can't see how you can be
> thrown by "not zero".
>
>
> > The "as" variant makes more sense when you read it as an
> > English sentence:
> >
> >if ((x - x_base) as diff) and ...
> >
> >"If x - x_base (and by the way, I'm going to call that
> > diff so I can refer to it later) is not zero ..."
>
> So read the original as "if diff (which is x - x_base) is not zero ...".
>
> Regardless, Guido has already said "as" is DOA (Dead On Arrival)
> (illustrating that it's also common enough in English to give a short
> name before its long-winded meaning ;-) ).
> ___
> 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] PEP 572: Assignment Expressions

2018-04-24 Thread Steve Holden
What facilities does the interpreter currently have for extracting common
subexpressions, and how would it verify in such a dynamic environment that
such extractions wouldn't alter the semantics of the program? Explicit
(assignment using :=) is better than implicit (by optimizations hidden to
the programmer).

regards
 Steve

Steve Holden

On Mon, Apr 23, 2018 at 6:13 PM, Sven R. Kunze  wrote:

> On 23.04.2018 17:59, Steve Holden wrote:
>
>
> While Tim's expression might look (superficially) like C, the five-line
> alternative isn't exactly an inspiring example of Pythonicity, is it?
>
>
> What about
>
> diff = x - x_base
> if diff and gcd(diff, n) > 1:
> return gcd(diff, n)
>
> # or
>
> if (x - x_base) and gcd(x - x_base, n) > 1:
> return gcd(x - x_base, n)
>
>
>
> and have the interpreter handle the optimization, or apply an lru_cache?
> ;-)
>
> Cheers,
> 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/
> steve%40holdenweb.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: Assignment Expressions

2018-04-24 Thread Antoine Pitrou
On Tue, 24 Apr 2018 01:55:13 -0500
Tim Peters  wrote:
> [Antoine]
> > Constructs like "with ..." or "try / except / finally" make the
> > language easier to learn compared to the dances they are meant to
> > replace.  
> 
> They nevertheless need to be taught & learned (and try/except/finally
> was essentially always in the language),  You snipped the parts
> pointing out that binding expressions are already familiar to people
> coming from most other languages

Yes... I think most will agree that Python is generally easy to take up
for people coming from C++ etc., so my "easier to learn and teach" was
mostly about non-programmers.

> even for raw beginners the
> semantics are the tiniest part of what they need to learn anyway about
> Python's assignment expressions.

I'm not sure what you mean by that.  If it's the tiniest part, what's
the overwhelming part?  Is the new assigment expression that delicate
to use that it requires reading a long and intimidating design
document ? I didn't get that impression, so it seems you may be making
a stronger point than me for rejeting the PEP :-)

> > "await" is a more readable and less confusing improvement
> > over "yield from".  
> 
> Heh.  Not to me.  I have literally have no idea what to with "await"
> (I use generators heavily, but have had no use yet for coroutines),
> but use
> 
> yield from an_iterable
> 
> routinely.

Yeah... "yield from" is fine for that, except that it was explicitly
meant for the coroutine use case as well (I'm not sure what the
timeline is, but probably Guido was already thinking/dreaming about
tulip/asyncio back then). And trying to shoehorn both in a single
construct made it confusing and inadequate.

When you want to express two abstractly different concepts (generating
a stream of values, or suspending a task until some asynchronous subtask
finishes), it makes things easier if those two concepts have two
different concrete expressions. Hence "await" making the language
easier to learn for those whose use cases benefit from it.

To bring another example: the fact that Python has separate syntax to
declare classes and functions makes it easier to learn "Python with
classes" than "Javascript with classes", even though the raw _grammar_
is made slightly more complex by it.  In Javascript you have to learn
the weird (ab)use of functional notation for the purpose of declaring
object behaviour, and learn to recognize it when you read it.  In
Python there's the "class" notation which, despite adding a keyword to
remember, makes class declaration easier to learn and master.

(^^ note this example is about a potentially obsolete dialect of
Javascript; perhaps it has class notation nowadays? ^^)

> It's simply impossible that, whatever "await" does, it
> could be more readable or less confusing than what I use "yield from"
> for.

Probably because "await" wouldn't work at all for you, then :-)

> >  Format strings dispense from the older, more convoluted formulations.  
> 
> But they didn't _replace_ them.  That made teaching/learning harder,
> not easier,

Intuitively, it sounds easier to teach f'some {value}' rather than
either the .format() or %-formatting alternatives.  The whole goal of
f-strings, after all, is to make string formatting more approachable.

Learning a language is not learning the whole spec.  When you learn C,
you don't need to learn the oddities of pre-ANSI function
declarations :-)

However, assignment a special case in this regard, since traditional
assignment is so omnipresent in online resources, that people _will_
encounter it even if they make a very focused use of Python.

> > Iteration is much simpler than the longer forms we would have to write
> > if generalized iterators didn't exist.  
> 
> I'll buy that one.  Now go through the HISTORY file and count all the
> changes you didn't name ;-)

You claimed that """almost no addition has ever made a language easier
to learn for raw beginners""".  I claim that several additions did
(for Python alone), but I don't need to prove that most of them did ;-)

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] PEP 572: Assignment Expressions

2018-04-24 Thread Jeff Allen

On 24/04/2018 02:42, Chris Jerdonek wrote:

On Mon, Apr 23, 2018 at 4:54 PM, Greg Ewing  wrote:

Tim Peters wrote:

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

My problem with this is -- how do you read such code out loud?

It could be...

"if diff, which we define as x - x_base, and g, which ." etc.

That's good. It also makes it natural to expect only a simple name. One 
can "define" a name, but assignment to a complex left-side expression is 
not definition (binding).


Jeff Allen
___
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: Assignment Expressions

2018-04-24 Thread Ivan Levkivskyi
On 24 April 2018 at 08:12, Greg Ewing  wrote:

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

>>>
> "if diff, which we let equal x - x_base, and g, which ..." or
>> "if diff, which we set equal to x - x_base, and g, which " or
>> "if diff, which we define to be x - x_base, and g, which " or
>> "if diff, which we define as x - x_base, and g, which ." etc.
>>
>
> How about "being" as a keyword:
>
>   if (diff being x - x_base) and (g being gcd(diff, n)) > 1:
> return g
>
> An advantage is that you're not likely to be tempted to write
>
>diff being x - x_base
>
> on its own as a statement.
>
>
I like this term, but I don't like having more reserved words. Or PEP can
make it an official way to read :=

(z := x + y) is _called_ a binding expression.
(z := x + y) _reads_ as "z being x + y"

--
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: Assignment Expressions

2018-04-24 Thread Tim Peters
[Stephen J. Turnbull[
>> Neologisms are usually written in the other order:
>> "dead on arrival (DOA, for short)." ;-)

[Greg Ewing ]
> Maybe we can make use of that?
>
>if (x - x_base) (diff) and gcd(diff, n) (g) > 1:
>
> That doesn't work, because the (...) look like function
> calls. But what if we used a different set of bracketing
> characters:
>
>if (x - x_base) {diff} and gcd(diff, n) {g} > 1:
>
> I think that's unambiguous, because you can't currently
> put {...} straight after an expression.

As Guido noted more than once when this was still on python-ideas,
this isn't a "a puzzle" to be solved by any technical tricks
conceivable.  He's not going to accept anything in his language that
isn't at least plausibly evident.  There's a long & distinguished
history of other languages using ":=" for binding, which is why that
one gained traction before this moved to python-dev.


> To make it look even more like a neologism definition,
> we could require the bound names to be all-uppercase. :-)
>
>if (x - x_base) {DIFF} and gcd(DIFF, n) {G} > 1:
>   return G

Yes - now you're on the right track ;-)
___
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: Assignment Expressions

2018-04-24 Thread Chris Angelico
On Tue, Apr 24, 2018 at 5:23 PM, Greg Ewing  wrote:
> Stephen J. Turnbull wrote:
>>
>> Neologisms are usually written in the
>> other order: "dead on arrival (DOA, for short)." ;-)
>
>
> Maybe we can make use of that?
>
>if (x - x_base) (diff) and gcd(diff, n) (g) > 1:
>
> That doesn't work, because the (...) look like function
> calls. But what if we used a different set of bracketing
> characters:
>
>if (x - x_base) {diff} and gcd(diff, n) {g} > 1:
>
> I think that's unambiguous, because you can't currently
> put {...} straight after an expression.
>
> To make it look even more like a neologism definition,
> we could require the bound names to be all-uppercase. :-)
>
>if (x - x_base) {DIFF} and gcd(DIFF, n) {G} > 1:
>   return G
>

Great! And to further enhance the neologism parallel, we could allow
them to be defined at the bottom of the program.

if {DIFF} and {G} > 1:
return G

with glossary:
DIFF: x - x_base
G: gcd(DIFF, n)


Definite improvement over all the current proposals!!

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: Assignment Expressions

2018-04-24 Thread Tim Peters
[Antoine Pitrou ]
> ...
> Having to break things out over multiple lines is a fact of life, if
> only for readability when implementing (and maintaining!) non-trivial
> processing routines. It's a good thing to be used to it, and to learn to
> choose good names for intermediate variables.

Well, the last part is overselling:  by its very nature, a binding
expression does not relieve the programmer one whit from needing to
pick good names.  The name is part of the binding expression.  The
sheer number of names needed is the same with or without binding
expressions, although the latter allow for less repetitive typing (&
reading) of those names.

For the rest, _needing_ to split a simple bind-and-test across two
lines doesn't really build character,  or have any other virtue
(besides familiarity to old-time Python programmers) I can see.
Neither does falling into indentation hell have any virtue in the
rarer cases where binding expressions really shine.  Simple things
_should_ be simple to do; indeed, when they are, that's an incentive
to keep things simple.

There will still be plenty of code where splitting multiple bindings
across multiple lines is obviously better.
___
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: Assignment Expressions

2018-04-24 Thread Chris Angelico
On Tue, Apr 24, 2018 at 5:12 PM, Greg Ewing  wrote:
> Chris Jerdonek wrote:
>
 if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
>
>
>> "if diff, which we let equal x - x_base, and g, which ..." or
>> "if diff, which we set equal to x - x_base, and g, which " or
>> "if diff, which we define to be x - x_base, and g, which " or
>> "if diff, which we define as x - x_base, and g, which ." etc.
>
>
> How about "being" as a keyword:
>
>   if (diff being x - x_base) and (g being gcd(diff, n)) > 1:
> return g
>
> An advantage is that you're not likely to be tempted to write
>
>diff being x - x_base
>
> on its own as a statement.

Considering that we have ':=', 'as', and 'from', I very much doubt
that *any* proposal requiring a new keyword is going to fly. The bar
for creating new keywords is a lot higher than that. We hashed out a
lot of this on python-ideas; it's almost certainly a waste of time to
go through it all again now. I have no intention of editing the PEP to
recommend a brand new keyword.

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: Assignment Expressions

2018-04-24 Thread Greg Ewing

Stephen J. Turnbull wrote:

Neologisms are usually written in the
other order: "dead on arrival (DOA, for short)." ;-)


Maybe we can make use of that?

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

That doesn't work, because the (...) look like function
calls. But what if we used a different set of bracketing
characters:

   if (x - x_base) {diff} and gcd(diff, n) {g} > 1:

I think that's unambiguous, because you can't currently
put {...} straight after an expression.

To make it look even more like a neologism definition,
we could require the bound names to be all-uppercase. :-)

   if (x - x_base) {DIFF} and gcd(DIFF, n) {G} > 1:
  return G

--
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] PEP 572: Assignment Expressions

2018-04-24 Thread Greg Ewing

Chris Jerdonek wrote:


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



"if diff, which we let equal x - x_base, and g, which ..." or
"if diff, which we set equal to x - x_base, and g, which " or
"if diff, which we define to be x - x_base, and g, which " or
"if diff, which we define as x - x_base, and g, which ." etc.


How about "being" as a keyword:

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

An advantage is that you're not likely to be tempted to write

   diff being x - x_base

on its own as a statement.

--
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] PEP 572: Assignment Expressions

2018-04-24 Thread Antoine Pitrou
On Tue, 24 Apr 2018 16:38:39 +1000
Chris Angelico  wrote:
> On Tue, Apr 24, 2018 at 4:27 PM, Antoine Pitrou  wrote:
> > On Tue, 24 Apr 2018 01:06:30 -0500
> > Tim Peters  wrote:  
> >>  
> >> > - does it make Python easier to learn and teach?  
> >>
> >> By whom?  Almost no addition has ever made a language easier to learn
> >> for raw beginners:  every addition is something they eventually need
> >> to learn.  We could make Python easier to learn for beginners by
> >> throwing out virtually everything added since version 0.9.6 ;-)  
> >
> > Constructs like "with ..." or "try / except / finally" make the
> > language easier to learn compared to the dances they are meant to
> > replace.  "await" is a more readable and less confusing improvement
> > over "yield from".  Format strings dispense from the older, more
> > convoluted formulations.  Iteration is much simpler than the longer
> > forms we would have to write if generalized iterators didn't exist.  
> 
> And assignment expressions are far simpler than breaking things out
> over multiple lines (particularly when you consider the infinite while
> loop alternative). But that doesn't change the fact that, as features,
> they do make the language harder to understand.

I did specifically say "easier to learn and teach" instead of using
generic phrases such as "simpler" or "harder to understand".  You won't
make Python easier to learn and teach by adding a new assignment
syntax, since people will have to learn the old form as well.

Having to break things out over multiple lines is a fact of life, if
only for readability when implementing (and maintaining!) non-trivial
processing routines. It's a good thing to be used to it, and to learn to
choose good names for intermediate variables.

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] PEP 572: Assignment Expressions

2018-04-23 Thread Tim Peters
[Antoine]
>>> - does it make Python easier to learn and teach?

[Tim]
>> By whom?  Almost no addition has ever made a language easier to learn
>> for raw beginners:  every addition is something they eventually need
>> to learn.  We could make Python easier to learn for beginners by
>> throwing out virtually everything added since version 0.9.6 ;-)

[Antoine]
> Constructs like "with ..." or "try / except / finally" make the
> language easier to learn compared to the dances they are meant to
> replace.

They nevertheless need to be taught & learned (and try/except/finally
was essentially always in the language),  You snipped the parts
pointing out that binding expressions are already familiar to people
coming from most other languages, and even for raw beginners the
semantics are the tiniest part of what they need to learn anyway about
Python's assignment expressions.

So that was my point:  they don't make Python any harder to learn or
teach.  To the contrary, for people coming from other languages, it's
one less thing they're used to they wouldn't have to _un_learn.


> "await" is a more readable and less confusing improvement
> over "yield from".

Heh.  Not to me.  I have literally have no idea what to with "await"
(I use generators heavily, but have had no use yet for coroutines),
but use

yield from an_iterable

routinely.  That use is perfectly clear, to the point that it _can't_
be improved on:  it already does exactly what I want from it, with no
effort at all.  It's simply impossible that, whatever "await" does, it
could be more readable or less confusing than what I use "yield from"
for.


>  Format strings dispense from the older, more convoluted formulations.

But they didn't _replace_ them.  They're Yet Another Way to Format
Strings everyone has to learn.  That made teaching/learning harder,
not easier, but you can make a case they make Python easier to _use_
for people who eschew the older forms.


> Iteration is much simpler than the longer forms we would have to write
> if generalized iterators didn't exist.

I'll buy that one.  Now go through the HISTORY file and count all the
changes you didn't name ;-)
___
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: Assignment Expressions

2018-04-23 Thread Chris Angelico
On Tue, Apr 24, 2018 at 4:27 PM, Antoine Pitrou  wrote:
> On Tue, 24 Apr 2018 01:06:30 -0500
> Tim Peters  wrote:
>>
>> > - does it make Python easier to learn and teach?
>>
>> By whom?  Almost no addition has ever made a language easier to learn
>> for raw beginners:  every addition is something they eventually need
>> to learn.  We could make Python easier to learn for beginners by
>> throwing out virtually everything added since version 0.9.6 ;-)
>
> Constructs like "with ..." or "try / except / finally" make the
> language easier to learn compared to the dances they are meant to
> replace.  "await" is a more readable and less confusing improvement
> over "yield from".  Format strings dispense from the older, more
> convoluted formulations.  Iteration is much simpler than the longer
> forms we would have to write if generalized iterators didn't exist.

And assignment expressions are far simpler than breaking things out
over multiple lines (particularly when you consider the infinite while
loop alternative). But that doesn't change the fact that, as features,
they do make the language harder to understand. The difference is that
they make *your program* easier to understand. If you really want the
*language* to be as easy as possible to fit into your head, you want a
Turing tarpit:

https://esolangs.org/wiki/Ook!

Only three lexical tokens, and only eight operations. But any program
written in Ook is going to be almost completely unreadable. That's the
tradeoff.

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: Assignment Expressions

2018-04-23 Thread Antoine Pitrou
On Tue, 24 Apr 2018 01:06:30 -0500
Tim Peters  wrote:
> 
> > - does it make Python easier to learn and teach?  
> 
> By whom?  Almost no addition has ever made a language easier to learn
> for raw beginners:  every addition is something they eventually need
> to learn.  We could make Python easier to learn for beginners by
> throwing out virtually everything added since version 0.9.6 ;-)

Constructs like "with ..." or "try / except / finally" make the
language easier to learn compared to the dances they are meant to
replace.  "await" is a more readable and less confusing improvement
over "yield from".  Format strings dispense from the older, more
convoluted formulations.  Iteration is much simpler than the longer
forms we would have to write if generalized iterators didn't exist.

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] PEP 572: Assignment Expressions

2018-04-23 Thread Tim Peters
[Steve Holden ]
>> ...
>> The assignment expression seems like a vary natural way to introduce
>> variables of limited (controlled?) scope, [...]

[Antoine Pitrou ]
> AFAIU, the scope isn't limited to the "if" block, it's a regular local
> variable.  I might have misread.

You're right about the current version of the PEP.  No new scoping
rules are introduced.  The PEP does suggest some changes to corner
case scoping semantics, though.


> ...
> Regardless, my three questions about this are:
> - does it make Python more powerful?

Goodness no.


> - does it make Python more readable?

There are cases where it would, and cases where it wouldn't.  People
shouldn't use it in the latter cases ;-)  I very recently wrote this
block of code:

outside = p2units[p1][tgt_kind] - units[2]
if outside:
if not all(self.crossout(q, n, undo)
 for q in outside):
return False

The opening pair is a very common minor annoyance; it's marginally
more readable like so:

if outside := p2units[p1][tgt_kind] - units[2]:

Saving an essentially useless line with a duplicated name is worth
something to me, because it comes up so very often.

But that's indeed "minor".  In my diff/gcd example, it reduced 5 lines
of code to 2; saved a level of annoying (semantically misleading)
indentation; and cut the number of instances of both "diff" and "g"
from 3 each to 2 each (ideal:  one each to bind the name, and then one
each to use the name later).  That's relatively substantial by any
measure.

In Guido's if/elif/elif/elif/elif ... complex text processing example
template, it can save an unbounded number of semantically needless
indentation levels.

So the readability benefits can range from highly negative to highly positive.


> - does it make Python easier to learn and teach?

By whom?  Almost no addition has ever made a language easier to learn
for raw beginners:  every addition is something they eventually need
to learn.  We could make Python easier to learn for beginners by
throwing out virtually everything added since version 0.9.6 ;-)

But people coming _from_ most other very widely used languages (C,
C++, Java, Javascript, Perl, ...) are already familiar with assignment
expressions.  The limited (to a plain identifier target) "binding
expression" PEP simplification I favor would be nothing new to them at
all (whereas the full complexity of Python's assignment statements is
indeed beyond what they're used to, but needs to be taught & learned
regardless of this PEP's fate).

At least when restricted to binding expressions, the syntax is simple
and the semantics are the very simplest case of what people (convert
or raw beginner) need to learn for Python's assignment statements
regardless.


> My answer would be "no" to all three, but YMMV.

And it did ;-)
___
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: Assignment Expressions

2018-04-23 Thread Stephen J. Turnbull
Tim Peters writes:

 > Regardless, Guido has already said "as" is DOA (Dead On Arrival)
 > (illustrating that it's also common enough in English to give a short
 > name before its long-winded meaning ;-) ).

The parens above are a gloss on a well-known acronym for those who
have not encountered it before.  Neologisms are usually written in the
other order: "dead on arrival (DOA, for short)." ;-)

___
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: Assignment Expressions

2018-04-23 Thread Chris Jerdonek
On Mon, Apr 23, 2018 at 4:54 PM, Greg Ewing  wrote:
> Tim Peters wrote:
>
>> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
>> return g
>
>
> My problem with this is -- how do you read such code out loud?

It could be--

"if diff, which we let equal x - x_base, and g, which ..." or
"if diff, which we set equal to x - x_base, and g, which " or
"if diff, which we define to be x - x_base, and g, which " or
"if diff, which we define as x - x_base, and g, which ." etc.

--Chris



>
> From my Pascal days I'm used to reading ":=" as "becomes". So
> this says:
>
>"If diff becomes x - base and g becomes gcd(diff, n) is
> greater than or equal to 1 then return g."
>
> But "diff becomes x - base" is not what we're testing! That
> makes it sound like the result of x - base may or may not
> get assigned to diff, which is not what's happening at all.
>
> The "as" variant makes more sense when you read it as an
> English sentence:
>
>if ((x - x_base) as diff) and ...
>
>"If x - x_base (and by the way, I'm going to call that
> diff so I can refer to it later) is not zero ..."
>
> --
> 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/chris.jerdonek%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: Assignment Expressions

2018-04-23 Thread Steven D'Aprano
On Mon, Apr 23, 2018 at 03:36:10PM -0700, Guido van Rossum wrote:
> Using 'as' was debated extensively on python-ideas. I don't like it for
> several reasons:
[...]

For what it is worth, I was one of the original proponents of the "as" 
syntax, but at this point I am no longer going to argue for it. I'm 
satisfied that using "as" has disadvantages, and that := is an 
acceptable alternative.

While I haven't changed my mind that putting the expression first and 
the target second is better, I'm satisfied that it is not so much better 
that it is worth extending this enormous discussion even further.

In other words, as far as I am concerned, I am happy to take the syntax 
as decided: "expr as name" is rejected and "name := expr" is acceptable.

I'm also satisfied that *at least for now* we should stick to only 
allowing simple names. We can always loosen the restriction later and 
allow arbitrarily complex targets at a later date, but we can't easily 
change our mind and prohibit them.



-- 
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: Assignment Expressions

2018-04-23 Thread Tim Peters
[Tim]
>> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
>> return g

[Greg Ewing ]
> My problem with this is -- how do you read such code out loud?

In the message in which I first gave that example:

if the diff isn't 0 and gcd(diff, n) > 1, return the gcd.
   That's how I _thought_ of it from the start.

In my mind, `x - x_base` doesn't even exist except as a low-level
definition of what "diff" means.  It's different for the other test:
_there_ `g` doesn't exist except as a shorthand for "the gcd".  In one
case it's the name that's important to me, and in the other case the
expression.  The entire function from which this came is doing all
arithmetic modulo `n`, so `n` isn't in my mind either - it's a
ubiquitous part of the background in this specific function.

But you did ask how_I_ would read that code ;-)  Anyone else is free
to read it however they like.  I naturally read it in the way that
makes most sense to me in its context.


> From my Pascal days I'm used to reading ":=" as "becomes". So
> this says:
>
>"If diff becomes x - base and g becomes gcd(diff, n) is
> greater than or equal to 1 then return g."
>
> But "diff becomes x - base" is not what we're testing!

I don't really follow that.  In Python,

if f() and g > 1:

first tests whether `f()` "is truthy", regardless of whether it does
or doesn't appear in a binding expression.  Because this code is
working with integers, there's an _implied_ "!= 0" comparison.


> That makes it sound like the result of x - base may or may not
> get assigned to diff, which is not what's happening at all.

Then I suggest the problem you're having doesn't stem from the binding
expression, but from that you're omitting to fill in the != 0 part:
if you're not thrown by "greater than 1", I can't see how you can be
thrown by "not zero".


> The "as" variant makes more sense when you read it as an
> English sentence:
>
>if ((x - x_base) as diff) and ...
>
>"If x - x_base (and by the way, I'm going to call that
> diff so I can refer to it later) is not zero ..."

So read the original as "if diff (which is x - x_base) is not zero ...".

Regardless, Guido has already said "as" is DOA (Dead On Arrival)
(illustrating that it's also common enough in English to give a short
name before its long-winded meaning ;-) ).
___
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: Assignment Expressions

2018-04-23 Thread Greg Ewing

Sven R. Kunze wrote:


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

and have the interpreter handle the optimization, or apply an lru_cache? ;-)


Problem is, there's no way to automatically tell whether
the expressions involved have side effects that are being
relied on.

--
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] PEP 572: Assignment Expressions

2018-04-23 Thread Greg Ewing

Tim Peters wrote:


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


My problem with this is -- how do you read such code out loud?

From my Pascal days I'm used to reading ":=" as "becomes". So
this says:

   "If diff becomes x - base and g becomes gcd(diff, n) is
greater than or equal to 1 then return g."

But "diff becomes x - base" is not what we're testing! That
makes it sound like the result of x - base may or may not
get assigned to diff, which is not what's happening at all.

The "as" variant makes more sense when you read it as an
English sentence:

   if ((x - x_base) as diff) and ...

   "If x - x_base (and by the way, I'm going to call that
diff so I can refer to it later) is not zero ..."

--
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] PEP 572: Assignment Expressions

2018-04-23 Thread Glenn Linderman

On 4/23/2018 1:01 PM, Ethan Furman wrote:

On 04/22/2018 10:44 PM, Tim Peters wrote:

[Guido]
In reality there often are other conditions being applied to the 
match for
which `if expr as name` is inadequate. The simplest would be 
something like


   if ...:
   
   elif (m := re.match('(.*):(.*)', line)) and m.group(1) == 
m.group(2):

 

And the match() call may not even be the first thing to check -- 
e.g. we

could have

 elif line is not None and (m := re.match('(.*):(.*)', line)) 
and m.group(1) == m.group(2):


I find myself warming more to binding expressions the more I keep them
in mind while writing new code.  And I think it may be helpful to
continue showing real examples where they would help.

Today's example:  I happened to code this a few hours ago:

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

It's not really hard to follow, but two levels of nesting "feels
excessive", as does using the names "diff" and "g" three times each.
It's _really_ an "and" test:  if the diff isn't 0 and gcd(diff, n) >
1, return the gcd.  That's how I _thought_ of it from the start.

Which this alternative expresses directly:

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


So I really like being able to make the assignment in the expression, 
but I have a really hard time parsing it with the name first.


Attempting to read just the names first:

  if
    diff
  scan for ending right paren
  found
  and
 g
  scan for ending right paren
    oops, found opening left paren
    scan for ending right paren
    found
  resume scanning for final right paren
  found
 > 1:
 return g


Attempting to read expressions first:

  if
    x - x_base
  and
    gcd(diff, n)
  what's diff?
    scan backwards
  diff is x - x_base
    > 1:
    return g
  what's g?
    scan up and backwards
    g is gcd(diff, n)


Attempting to read interleaved:

  if
    skip diff
  x - x_base
  back to diff
    as diff
  and
    skip g
  gcd(diff, n)
  back to g
    as g
  > 1:
  return g


On the other hand, if it were using the "as" keyword:

if (x - xbase as diff) and (gcd(diff, n) as g) > 1:
    return g

I would parse as:

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

For me at least, the last is much more readable.  Thinking about it 
some more, the problem (or maybe just my problem) is that I see an 
"if" or "while" and the I look for the thing that is True or False, 
and using the ":=" syntax the first thing I see is a placeholder for a 
result that doesn't exist yet, making me constantly scan backwards and 
forwards to put all the pieces in the correct place.


With "as", it just flows forwards.


You need to borrow the time machine, and get with those early 
mathematicians that first said:


Let x be the sum of y and z

and convince them that what they should have said was:

Let the sum of y and z be called x.

:)
___
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: Assignment Expressions

2018-04-23 Thread Matěj Cepl
On 2018-04-23, 21:34 GMT, Sven R. Kunze wrote:
> Is it just me or since when has the following Python code 
> fallen out of favor?

It isn’t just you.

Matěj
-- 
https://matej.ceplovi.cz/blog/, Jabber: mc...@ceplovi.cz
GPG Finger: 3C76 A027 CA45 AD70 98B5  BC1D 7920 5802 880B C9D8
 
… one of the main causes of the fall of the Roman Empire was
that, lacking zero, they had no way to indicate successful
termination of their C programs.  
  -- Robert Firth

___
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: Assignment Expressions

2018-04-23 Thread Guido van Rossum
Using 'as' was debated extensively on python-ideas. I don't like it for
several reasons:

- the semantics are subtly different from all other uses of 'as' in Python;
I'd like to reserve 'as' for "not a plain assignment"
- a short word is easier to miss when skimming code than punctuation
- most other languages (Java*, C*) borrow from assignment (name = expr)


On Mon, Apr 23, 2018 at 3:19 PM, Ned Deily  wrote:

> On Apr 23, 2018, at 18:04, Tim Peters  wrote:
> > However, against "as" is that its current use in "with" statements
> > does something quite different:
> >
> >with f() as name:
> >
> > does not bind the result of `f()` to `name`, but the result of
> > `f().__enter__()`.  Whether that "should be" fatal, I don't know, but
> > it's at least annoying ;-)
>
> Prior art: COBOL uses "GIVING", as in:
>
>ADD x, y GIVING z
>
> No need to re-invent the wheel ;)
>
> --
>   Ned Deily
>   n...@python.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/
> 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] PEP 572: Assignment Expressions

2018-04-23 Thread Paul G
On 04/23/2018 06:04 PM, Tim Peters wrote:

> However, against "as" is that its current use in "with" statements
> does something quite different:
> 
> with f() as name:
> 
> does not bind the result of `f()` to `name`, but the result of
> `f().__enter__()`.  Whether that "should be" fatal, I don't know, but
> it's at least annoying ;-)


This could be read a different way, though, since `with f()` calls 
`f().__enter__()`, you could read it as `(with f()) as name:`, in which case it 
does the same thing as an `as`-based binding expression would. Viewing it that 
way *also* helps alleviate the cognitive problem that `with f() as name` and 
`with (f() as name)` do two different things - the parentheses there are 
changing the precedence in the same way that `2 + 4 * 3` and `(2 + 4) * 3` do 
two different things.

This sorta also works for `except`, if you read it as `(except SomeException) 
as e:`, but I think this fiction falls apart when you look at `import`, since 
`import foo` *already* binds "foo" to a name, and `import foo as bar` not only 
binds `foo` to `bar`, but also *doesn't* bind `foo` to `foo`.



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] PEP 572: Assignment Expressions

2018-04-23 Thread Ned Deily
On Apr 23, 2018, at 18:04, Tim Peters  wrote:
> However, against "as" is that its current use in "with" statements
> does something quite different:
> 
>with f() as name:
> 
> does not bind the result of `f()` to `name`, but the result of
> `f().__enter__()`.  Whether that "should be" fatal, I don't know, but
> it's at least annoying ;-)

Prior art: COBOL uses "GIVING", as in:

   ADD x, y GIVING z

No need to re-invent the wheel ;)

--
  Ned Deily
  n...@python.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: Assignment Expressions

2018-04-23 Thread Guido van Rossum
Whereas I find it a deal-breaker for 'as'.

On Mon, Apr 23, 2018 at 3:15 PM, Ethan Furman  wrote:

> On 04/23/2018 03:04 PM, Tim Peters wrote:
>
>> [Ethan Furman ]
>>
>>> So I really like being able to make the assignment in the expression,
>>> but I
>>> have a really hard time parsing it with the name first.
>>>
>>> ...
>>>
>>> On the other hand, if it were using the "as" keyword:
>>>
>>> if (x - xbase as diff) and (gcd(diff, n) as g) > 1:
>>>  return g
>>>
>>> I would parse as:
>>>
>>>if
>>>  x - x_base
>>>  as diff
>>>and
>>>  gcd(diff, n)
>>>  as g
>>>> 1:
>>>return g
>>>
>>> For me at least, the last is much more readable.  Thinking about it some
>>> more, the problem (or maybe just my problem) is that I see an "if" or
>>> "while" and the I look for the thing that is True or False, and using the
>>> ":=" syntax the first thing I see is a placeholder for a result that
>>> doesn't
>>> exist yet, making me constantly scan backwards and forwards to put all
>>> the
>>> pieces in the correct place.
>>>
>>> With "as", it just flows forwards.
>>>
>>
>> I can read it fine either way, and don't much care.  A possible
>> advantage of an "as" operator is that its precedence could be set to
>> bind just a tad stronger than comparisons (which include "is" and "is
>> not" in Python), and then, e.g.,
>>
>>  if f() as result is not None:
>>  do something with result
>>
>> could work as intended.  So long as people can't get "assignment
>> _statements_" out of their heads,
>>
>>  if result := f() is not None:
>>
>> groups instead as
>>
>>  if result := (f() is not None):
>>
>> which would almost never be _intended_.  Maybe spelling it "as"
>> instead could break that.
>>
>> However, against "as" is that its current use in "with" statements
>> does something quite different:
>>
>>  with f() as name:
>>
>> does not bind the result of `f()` to `name`, but the result of
>> `f().__enter__()`.  Whether that "should be" fatal, I don't know, but
>> it's at least annoying ;-)
>>
>
> "as" does something slightly different in each of its current
> incantations, but the one thing that they all have in common is taking some
> thing on the left and giving it the name on the right:
>
> - imports -> thing on left gets name on right
> - exceptions -> exception that matches class on left gets name on right
> - with -> result of left.__enter__() gets name on right
>
> I see very little harm in adding
>
> - expression-binding -> eval(thing on left) gets name on right
>
> --
> ~Ethan~
>
>
> ___
> 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] PEP 572: Assignment Expressions

2018-04-23 Thread Ethan Furman

On 04/23/2018 03:04 PM, Tim Peters wrote:

[Ethan Furman ]

So I really like being able to make the assignment in the expression, but I
have a really hard time parsing it with the name first.

...

On the other hand, if it were using the "as" keyword:

if (x - xbase as diff) and (gcd(diff, n) as g) > 1:
 return g

I would parse as:

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

For me at least, the last is much more readable.  Thinking about it some
more, the problem (or maybe just my problem) is that I see an "if" or
"while" and the I look for the thing that is True or False, and using the
":=" syntax the first thing I see is a placeholder for a result that doesn't
exist yet, making me constantly scan backwards and forwards to put all the
pieces in the correct place.

With "as", it just flows forwards.


I can read it fine either way, and don't much care.  A possible
advantage of an "as" operator is that its precedence could be set to
bind just a tad stronger than comparisons (which include "is" and "is
not" in Python), and then, e.g.,

 if f() as result is not None:
 do something with result

could work as intended.  So long as people can't get "assignment
_statements_" out of their heads,

 if result := f() is not None:

groups instead as

 if result := (f() is not None):

which would almost never be _intended_.  Maybe spelling it "as"
instead could break that.

However, against "as" is that its current use in "with" statements
does something quite different:

 with f() as name:

does not bind the result of `f()` to `name`, but the result of
`f().__enter__()`.  Whether that "should be" fatal, I don't know, but
it's at least annoying ;-)


"as" does something slightly different in each of its current incantations, but the one thing that they all have in 
common is taking some thing on the left and giving it the name on the right:


- imports -> thing on left gets name on right
- exceptions -> exception that matches class on left gets name on right
- with -> result of left.__enter__() gets name on right

I see very little harm in adding

- expression-binding -> eval(thing on left) gets name on right

--
~Ethan~

___
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: Assignment Expressions

2018-04-23 Thread Tim Peters
[Ethan Furman ]
> So I really like being able to make the assignment in the expression, but I
> have a really hard time parsing it with the name first.
>
> ...
>
> On the other hand, if it were using the "as" keyword:
>
> if (x - xbase as diff) and (gcd(diff, n) as g) > 1:
> return g
>
> I would parse as:
>
>   if
> x - x_base
> as diff
>   and
> gcd(diff, n)
> as g
>   > 1:
>   return g
>
> For me at least, the last is much more readable.  Thinking about it some
> more, the problem (or maybe just my problem) is that I see an "if" or
> "while" and the I look for the thing that is True or False, and using the
> ":=" syntax the first thing I see is a placeholder for a result that doesn't
> exist yet, making me constantly scan backwards and forwards to put all the
> pieces in the correct place.
>
> With "as", it just flows forwards.

I can read it fine either way, and don't much care.  A possible
advantage of an "as" operator is that its precedence could be set to
bind just a tad stronger than comparisons (which include "is" and "is
not" in Python), and then, e.g.,

if f() as result is not None:
do something with result

could work as intended.  So long as people can't get "assignment
_statements_" out of their heads,

if result := f() is not None:

groups instead as

if result := (f() is not None):

which would almost never be _intended_.  Maybe spelling it "as"
instead could break that.

However, against "as" is that its current use in "with" statements
does something quite different:

with f() as name:

does not bind the result of `f()` to `name`, but the result of
`f().__enter__()`.  Whether that "should be" fatal, I don't know, but
it's at least annoying ;-)
___
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: Assignment Expressions

2018-04-23 Thread Tim Peters
[Tim]
>> Surely you're joking.  This is math.gcd(), which is expensive for
>> multi-thousand bit integers, and the interpreter knows nothing about
>> it.  Adding a cache of _any_ kind (LRU or otherwise) would make it
>> even slower.

[Sven R. Kunze ]
> Alright, if that problem is just about performance,

It's not, but others had already pointed out that it's generally
considered Poor Practice (and for good reasons) to textually repeat
expressions, so I didn't echo that.  Even in purely functional
languages, where textually equal snippets are guaranteed to evaluate
to the same result every time, "give these expressions these brief
names" constructs are heavily used (see, .e.g, "let" and "where" in
Haskell).


>:then there must be a better way to resolve it rather than
> inventing a new syntax.

Why?  "Give the result of an expression a name" is already heavily
used in Python - it's just that the _contexts_ in which it can be done
are very limited now.


> Btw. storing the result in a local var is also a cache IMHO. And
> if gcd is immutable, I think Python can do a great job here of
> optimizing.

After decades, CPython still does nothing of the sort, short of having
eventually made, e.g., "None" and "True" and "False" reserved words so
at least it can optimize uses of those.  It knows nothing at all about
which library functions are pure - and there's no code in the
implementation currently capable of exploiting such information even
if it were known.  That remains a fantasy in CPython.


> Anyway, your example is the best one I've seen so far.

Guido gave better ones, where binding expressions would allow to
collapse arbitrarily deep levels of nesting to just one (if ... elif
... elif ... elif ...).  My example only eliminated a single level of
artificial indentation.  But my example did have the advantage of
being taken verbatim from actual, working 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] PEP 572: Assignment Expressions

2018-04-23 Thread Sven R. Kunze

On 23.04.2018 23:19, Barry Warsaw wrote:

I also think it effectively solves the switch-statement problem:

if (get_response() as answer) == 'yes':
 do_it()
elif answer == 'no':
 skip_it()
elif answer == 'maybe'
 okay_then()

That’s Pythonic enough for jazz!


Is it just me or since when has the following Python code fallen out of 
favor?


answer = get_response()
if answer == 'yes':
do_it()
elif answer == 'no':
skip_it()
elif answer == 'maybe'
okay_then()

I really don't see anything I would want to optimize here. Not even a 
single bit. But as said that might just be me.


What I like about this code is:
1) symmetry: all ifs are equally structured
2) classic IPO model: first get input, then process (, then output)

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] PEP 572: Assignment Expressions

2018-04-23 Thread Chris Angelico
On Tue, Apr 24, 2018 at 7:25 AM, Sven R. Kunze  wrote:
> On 23.04.2018 22:37, Chris Angelico wrote:
>>
>> Ah, are you one of those programmers who writes code once and it's
>> instantly perfect? I apologize, I didn't realize I was in the presence
>> of a unicorn.
>
>
> Wow, constructive. Nothing is perfect, but if you don't consider your
> surroundings when doing changes, well, what could possibly go wrong...

I've seen way too many programmers - myself included - think that
synchronized edits are viable. If you are the one and only perfect
programmer, then sure! But if you're like the rest of us, it's better
to build your code in such a way that it doesn't bite you.

Yes, it was a snarky way to make the point, but I have a strong point to make.

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: Assignment Expressions

2018-04-23 Thread Sven R. Kunze

On 23.04.2018 22:37, Chris Angelico wrote:

Ah, are you one of those programmers who writes code once and it's
instantly perfect? I apologize, I didn't realize I was in the presence
of a unicorn.


Wow, constructive. Nothing is perfect, but if you don't consider your 
surroundings when doing changes, well, what could possibly go wrong...



Duplication works against that by forcing you to make changes in two places.


... in the very same line, a line below, few characters after/before it.


I've seen code that relies on duplication and compiler optimizations.
Sure, it'll run just as fast as the equivalent with actual variable
names; but that's beside the point. It takes extra effort to maintain
such code, and that is what matters.


That's exactly my point. Readability is what counts, especially for 
maintaining. "gcd(diff, n)" is a great name, much better than "g", if 
you ask me.


We aren't talking about 1000 lines of code here. The new syntax will 
enable one-liner optimizations. And I think Tim's example is as good as 
we can get realistically. Because if the expressions become longer or 
more complex and/or the numbers of expressions increase, I doubt that a 
majority want to have that in a single line even though the syntax would 
allow this. And if so the editor might include some line wraps, so then 
we are where we were before. Somewhere, you need to get your hands dirty.

___
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: Assignment Expressions

2018-04-23 Thread Barry Warsaw
On Apr 23, 2018, at 13:01, Ethan Furman  wrote:
> 
> On 04/22/2018 10:44 PM, Tim Peters wrote:
>> 
>> 
>> I find myself warming more to binding expressions the more I keep them
>> in mind while writing new code.

And I really like the term “binding expressions” because that’s how I think 
about this feature. I also think it will be easier to explain because “all it 
does” is bind a value to a name, and to me that’s the most powerful and 
valuable thing behind this feature.

> So I really like being able to make the assignment in the expression, but I 
> have a really hard time parsing it with the name first.

Me too.  Plus we *already* have precedence for spelling name bindings in 
similar constructs, such as import statements, with statements, and exceptions. 
 It seems like a natural and Pythonic approach to extend that same spelling to 
binding expressions rather than introducing new, weird, symbols.

I also think it effectively solves the switch-statement problem:

if (get_response() as answer) == 'yes':
do_it()
elif answer == 'no':
skip_it()
elif answer == 'maybe'
okay_then()

That’s Pythonic enough for jazz!

-Barry



signature.asc
Description: Message signed with OpenPGP
___
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: Assignment Expressions

2018-04-23 Thread Chris Angelico
On Tue, Apr 24, 2018 at 6:21 AM, Sven R. Kunze  wrote:
> On 23.04.2018 19:24, Chris Angelico wrote:
>>
>> On Tue, Apr 24, 2018 at 3:13 AM, Sven R. Kunze  wrote:
>>>
>>> diff = x - x_base
>>> if diff and gcd(diff, n) > 1:
>>>  return gcd(diff, n)
>>>
>>> # or
>>>
>>> if (x - x_base) and gcd(x - x_base, n) > 1:
>>>  return gcd(x - x_base, n)
>>>
>>>
>>> and have the interpreter handle the optimization, or apply an lru_cache?
>>> ;-)
>>
>> And then you want to change something, and you have to make an edit in
>> two places. Or, worse, you make it in only one of those places, they
>> become desynchronized, and nobody can figure out why the program
>> occasionally and bizarrely fails.
>
>
> If you change any of those lines (including ones of my fore-posters) without
> knowing what you're doing, you'd better don't touch them at all.
>
> The SQL folks btw. are pretty okay'ish with this kind of duplication because
> they can resolve it. Surely, Python isn't SQL but sometimes I wish Python
> could handle such things as easily without me having to babysit it all the
> time and using Perl'ish syntax (which := looks like to me). We then have :=,
> = and ==. Sorry, but Python wouldn't fit my brain then.
>

Ah, are you one of those programmers who writes code once and it's
instantly perfect? I apologize, I didn't realize I was in the presence
of a unicorn.

Most programmers will end up making edits to all non-trivial code. And
if your code is laid out in such a way that edits are easier and
safer, you're less likely to introduce bugs as you edit. Duplication
works against that by forcing you to make changes in two places.

I've seen code that relies on duplication and compiler optimizations.
Sure, it'll run just as fast as the equivalent with actual variable
names; but that's beside the point. It takes extra effort to maintain
such code, and that is what matters.

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: Assignment Expressions

2018-04-23 Thread Sven R. Kunze

On 23.04.2018 19:31, Tim Peters wrote:

Surely you're joking.  This is math.gcd(), which is expensive for
multi-thousand bit integers, and the interpreter knows nothing about
it.  Adding a cache of _any_ kind (LRU or otherwise) would make it
even slower.
Alright, if that problem is just about performance, then there must be a 
better way to resolve it rather than inventing a new syntax. Btw. 
storing the result in a local var is also a cache IMHO. And if gcd is 
immutable, I think Python can do a great job here of optimizing.


Anyway, your example is the best one I've seen so far.

___
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: Assignment Expressions

2018-04-23 Thread Sven R. Kunze

On 23.04.2018 19:24, Chris Angelico wrote:

On Tue, Apr 24, 2018 at 3:13 AM, Sven R. Kunze  wrote:

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

# or

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


and have the interpreter handle the optimization, or apply an lru_cache? ;-)

And then you want to change something, and you have to make an edit in
two places. Or, worse, you make it in only one of those places, they
become desynchronized, and nobody can figure out why the program
occasionally and bizarrely fails.


If you change any of those lines (including ones of my fore-posters) 
without knowing what you're doing, you'd better don't touch them at all.


The SQL folks btw. are pretty okay'ish with this kind of duplication 
because they can resolve it. Surely, Python isn't SQL but sometimes I 
wish Python could handle such things as easily without me having to 
babysit it all the time and using Perl'ish syntax (which := looks like 
to me). We then have :=, = and ==. Sorry, but Python wouldn't fit my 
brain then.

___
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: Assignment Expressions

2018-04-23 Thread Ethan Furman

On 04/22/2018 10:44 PM, Tim Peters wrote:

[Guido]

In reality there often are other conditions being applied to the match for
which `if expr as name` is inadequate. The simplest would be something like

   if ...:
   
   elif (m := re.match('(.*):(.*)', line)) and m.group(1) == m.group(2):
 

And the match() call may not even be the first thing to check -- e.g. we
could have

 elif line is not None and (m := re.match('(.*):(.*)', line)) and 
m.group(1) == m.group(2):


I find myself warming more to binding expressions the more I keep them
in mind while writing new code.  And I think it may be helpful to
continue showing real examples where they would help.

Today's example:  I happened to code this a few hours ago:

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

It's not really hard to follow, but two levels of nesting "feels
excessive", as does using the names "diff" and "g" three times each.
It's _really_ an "and" test:  if the diff isn't 0 and gcd(diff, n) >
1, return the gcd.  That's how I _thought_ of it from the start.

Which this alternative expresses directly:

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


So I really like being able to make the assignment in the expression, but I have a really hard time parsing it with the 
name first.


Attempting to read just the names first:

  if
diff
  scan for ending right paren
  found
  and
 g
  scan for ending right paren
oops, found opening left paren
scan for ending right paren
found
  resume scanning for final right paren
  found
 > 1:
 return g


Attempting to read expressions first:

  if
x - x_base
  and
gcd(diff, n)
  what's diff?
scan backwards
  diff is x - x_base
> 1:
return g
  what's g?
scan up and backwards
g is gcd(diff, n)


Attempting to read interleaved:

  if
skip diff
  x - x_base
  back to diff
as diff
  and
skip g
  gcd(diff, n)
  back to g
as g
  > 1:
  return g


On the other hand, if it were using the "as" keyword:

if (x - xbase as diff) and (gcd(diff, n) as g) > 1:
return g

I would parse as:

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

For me at least, the last is much more readable.  Thinking about it some more, the problem (or maybe just my problem) is 
that I see an "if" or "while" and the I look for the thing that is True or False, and using the ":=" syntax the first 
thing I see is a placeholder for a result that doesn't exist yet, making me constantly scan backwards and forwards to 
put all the pieces in the correct place.


With "as", it just flows forwards.

--
~Ethan~
___
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: Assignment Expressions

2018-04-23 Thread Antoine Pitrou
On Mon, 23 Apr 2018 16:59:35 +0100
Steve Holden  wrote:
> On Mon, Apr 23, 2018 at 8:28 AM, Antoine Pitrou  wrote:
> 
> > On Mon, 23 Apr 2018 00:44:44 -0500
> > Tim Peters  wrote:
> > ​[...]
> >  
> > > if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
> > > return g
> > > That's so Pythonic I could cry ;-)  
> >
> > ​[...]
> >
> > The second part, especially, where you use the result of an
> > assignment expression as a comparison operand, looks definitely
> > un-Pythonic.
> >
> ​Which, I suppose, underlines that Pythonicity is in the mind of the  
> beholder.​

Indeed it is.  What we can only say is that the proposed idiom goes
against current Python syntactical rules :-)

> The assignment expression seems like a vary natural way to introduce
> variables of limited (controlled?) scope, [...]

AFAIU, the scope isn't limited to the "if" block, it's a regular local
variable.  I might have misread.

> While Tim's expression might look (superficially) like C, the five-line
> alternative isn't exactly an inspiring example of Pythonicity, is it?

I don't know.  I've written my share of similar-looking code and I've
never really been bothered, at least not enough that I thought we
should change the language to accomodate those use cases.  To be frank
I don't remember the last time I was bothered by an aspect of Python's
syntax.  I think the language has reached "peak syntax" by now and it
should basically be frozen, and any improvements targeted at other
aspects (semantics, performance, stdlib, etc.).

Regardless, my three questions about this are:
- does it make Python more powerful?
- does it make Python more readable?
- does it make Python easier to learn and teach?

My answer would be "no" to all three, but YMMV.

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] PEP 572: Assignment Expressions

2018-04-23 Thread Tim Peters
[Sven R. Kunze ]
> What about
>
> diff = x - x_base
> if diff and gcd(diff, n) > 1:
> return gcd(diff, n)
>
> # or
>
> if (x - x_base) and gcd(x - x_base, n) > 1:
> return gcd(x - x_base, n)
>
>
> and have the interpreter handle the optimization, or apply an lru_cache? ;-)

Surely you're joking.  This is math.gcd(), which is expensive for
multi-thousand bit integers, and the interpreter knows nothing about
it.  Adding a cache of _any_ kind (LRU or otherwise) would make it
even slower (in the application, there's no reason to expect that x -
x_base will repeat a value before O(sqrt(n)) iterations, which itself
can be thousands of bits - a cache hit would be a miracle).
___
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: Assignment Expressions

2018-04-23 Thread Chris Angelico
On Tue, Apr 24, 2018 at 3:13 AM, Sven R. Kunze  wrote:
> On 23.04.2018 17:59, Steve Holden wrote:
>
>
> While Tim's expression might look (superficially) like C, the five-line
> alternative isn't exactly an inspiring example of Pythonicity, is it?
>
>
> What about
>
> diff = x - x_base
> if diff and gcd(diff, n) > 1:
> return gcd(diff, n)
>
> # or
>
> if (x - x_base) and gcd(x - x_base, n) > 1:
> return gcd(x - x_base, n)
>
>
> and have the interpreter handle the optimization, or apply an lru_cache? ;-)

And then you want to change something, and you have to make an edit in
two places. Or, worse, you make it in only one of those places, they
become desynchronized, and nobody can figure out why the program
occasionally and bizarrely fails. Removing duplicate function calls
isn't just about run-time performance.

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: Assignment Expressions

2018-04-23 Thread Sven R. Kunze

On 23.04.2018 17:59, Steve Holden wrote:


While Tim's expression might look (superficially) like C, the 
five-line alternative isn't exactly an inspiring example of 
Pythonicity, is it?




What about

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

# or

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


and have the interpreter handle the optimization, or apply an lru_cache? ;-)

Cheers,
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] PEP 572: Assignment Expressions

2018-04-23 Thread Steve Holden
On Mon, Apr 23, 2018 at 8:28 AM, Antoine Pitrou  wrote:

> On Mon, 23 Apr 2018 00:44:44 -0500
> Tim Peters  wrote:
> ​[...]
>
> > if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
> > return g
> > That's so Pythonic I could cry ;-)
>
> ​[...]
>
> The second part, especially, where you use the result of an
> assignment expression as a comparison operand, looks definitely
> un-Pythonic.
>
> ​Which, I suppose, underlines that Pythonicity is in the mind of the
beholder.​


The assignment expression seems like a vary natural way to introduce
variables of limited (controlled?) scope, and the class-namespace special
case doesn't seem horrible enough to put me, at least, off the idea. There
will, of course, be those who abuse assignment expressions, and I'm very
much looking forward to seeing what David Beazley makes of them.

While Tim's expression might look (superficially) like C, the five-line
alternative isn't exactly an inspiring example of Pythonicity, is it?

regards
 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: Assignment Expressions

2018-04-23 Thread Tim Peters
[Tim]
>> Which this alternative expresses directly:
>>
>> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
>> return g
>>
>> That's so Pythonic I could cry ;-)

[Antoine]
> It looks like C to me.  That won't make me cry (I write C++ code daily
> these days), but it's certainly not the same language as Python.
>
> The second part, especially, where you use the result of an
> assignment expression as a comparison operand, looks definitely
> un-Pythonic.

You snipped the part explaining _what's_ "Pythonic" about it:

It's _really_ an "and" test:  if the diff isn't 0 and gcd(diff, n) >
1, return the gcd.  That's how I _thought_ of it from the start.

"Expresses directly" is the Pythonic part; the syntax is minor to me.
Seeing that the _intent_ is an "and test" is a pattern-matching puzzle
in the original spelling (which essentially turned me into a compiler,
writing low-level code for the _concepts_ I had in mind from the
start):

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

But note that the part of the PEP I support is just the "binding
expression" part:  giving a simple name (binding an identifier) to the
result of an expression.  I don't want the full potential complexity
of assignment statements in expressions.  There's nothing
"un-Pythonic" about merely giving a name to an expression result,
apart from that there are few contexts that currently support that in
a sanely usable way.
___
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: Assignment Expressions

2018-04-23 Thread Antoine Pitrou
On Mon, 23 Apr 2018 00:44:44 -0500
Tim Peters  wrote:
> 
> Which this alternative expresses directly:
> 
> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
> return g
> 
> That's so Pythonic I could cry ;-)

It looks like C to me.  That won't make me cry (I write C++ code daily
these days), but it's certainly not the same language as Python.

The second part, especially, where you use the result of an
assignment expression as a comparison operand, looks definitely
un-Pythonic.

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] PEP 572: Assignment Expressions

2018-04-22 Thread Tim Peters
[Guido]
> In reality there often are other conditions being applied to the match for
> which `if expr as name` is inadequate. The simplest would be something like
>
>   if ...:
>   
>   elif (m := re.match('(.*):(.*)', line)) and m.group(1) == m.group(2):
> 
>
> And the match() call may not even be the first thing to check -- e.g. we
> could have
>
> elif line is not None and (m := re.match('(.*):(.*)', line)) and 
> m.group(1) == m.group(2):

I find myself warming more to binding expressions the more I keep them
in mind while writing new code.  And I think it may be helpful to
continue showing real examples where they would help.

Today's example:  I happened to code this a few hours ago:

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

It's not really hard to follow, but two levels of nesting "feels
excessive", as does using the names "diff" and "g" three times each.
It's _really_ an "and" test:  if the diff isn't 0 and gcd(diff, n) >
1, return the gcd.  That's how I _thought_ of it from the start.

Which this alternative expresses directly:

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

That's so Pythonic I could cry ;-)
___
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: Assignment Expressions

2018-04-22 Thread Guido van Rossum
Please stop debating ` as `. Nobody is being swayed by anything
in this subthread. Let's move on.

On Sun, Apr 22, 2018 at 3:27 PM, Chris Angelico  wrote:

> On Mon, Apr 23, 2018 at 8:20 AM, Mike Miller 
> wrote:
> >
> > On 2018-04-22 14:33, Chris Angelico wrote:
> >>
> >> with open(fn) as f:
> >> with (open(fn) as f):
> >>
> >> These two do the same thing, but only because a file object's
> >> __enter__ returns self. So it's dangerous, because it WILL work... and
> >> people will get into the habit of parenthesizing to permit a 'with'
> >> statement to go across line breaks. And then they'll use a different
> >> context manager, like closing(), or a PsycoPG2 database connection (I
> >> think), where it returns something else. And it'll work, until they go
> >> over multiple lines, and then suddenly the semantics change.
> >
> >
> >
> > Why do you think folks will be rushing to parenthesize with statements
> when
> > it has always been a syntax error, there is years of code and docs that
> show
> > otherwise, no use cases, and will take years for 3.8 to trickle out?
>
> Because it's been requested a number of times as a way to allow a
> 'with' statement to go across lines without backslashes.
>
> If it becomes possible, it will be used.
>
> 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/
> 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] PEP 572: Assignment Expressions

2018-04-22 Thread Guido van Rossum
On Sun, Apr 22, 2018 at 3:13 PM, Steve Dower  wrote:

> This example makes me want “if expr as name:” (same semantics as ‘with’,
> and the name is always bound to the expression result regardless of
> truthiness), but doesn’t move me on assignment expressions.
>

In reality there often are other conditions being applied to the match for
which `if expr as name` is inadequate. The simplest would be something like

  if ...:
  
  elif (m := re.match('(.*):(.*)', line)) and m.group(1) == m.group(2):


And the match() call may not even be the first thing to check -- e.g. we
could have

elif line is not None and (m := re.match('(.*):(.*)', line)) and
m.group(1) == m.group(2):

-- 
--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] PEP 572: Assignment Expressions

2018-04-22 Thread Chris Angelico
On Mon, Apr 23, 2018 at 8:20 AM, Mike Miller  wrote:
>
> On 2018-04-22 14:33, Chris Angelico wrote:
>>
>> with open(fn) as f:
>> with (open(fn) as f):
>>
>> These two do the same thing, but only because a file object's
>> __enter__ returns self. So it's dangerous, because it WILL work... and
>> people will get into the habit of parenthesizing to permit a 'with'
>> statement to go across line breaks. And then they'll use a different
>> context manager, like closing(), or a PsycoPG2 database connection (I
>> think), where it returns something else. And it'll work, until they go
>> over multiple lines, and then suddenly the semantics change.
>
>
>
> Why do you think folks will be rushing to parenthesize with statements when
> it has always been a syntax error, there is years of code and docs that show
> otherwise, no use cases, and will take years for 3.8 to trickle out?

Because it's been requested a number of times as a way to allow a
'with' statement to go across lines without backslashes.

If it becomes possible, it will be used.

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: Assignment Expressions

2018-04-22 Thread Mike Miller


On 2018-04-22 14:33, Chris Angelico wrote:

with open(fn) as f:
with (open(fn) as f):

These two do the same thing, but only because a file object's
__enter__ returns self. So it's dangerous, because it WILL work... and
people will get into the habit of parenthesizing to permit a 'with'
statement to go across line breaks. And then they'll use a different
context manager, like closing(), or a PsycoPG2 database connection (I
think), where it returns something else. And it'll work, until they go
over multiple lines, and then suddenly the semantics change.



Why do you think folks will be rushing to parenthesize with statements when it 
has always been a syntax error, there is years of code and docs that show 
otherwise, no use cases, and will take years for 3.8 to trickle out?


Seems remote, and there are mitigations that could be done.

Again it's back to "people could write bad code," but they already can with only 
+/* and ().


-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] PEP 572: Assignment Expressions

2018-04-22 Thread Steve Dower
This example makes me want “if expr as name:” (same semantics as ‘with’, and 
the name is always bound to the expression result regardless of truthiness), 
but doesn’t move me on assignment expressions.

Cheers,
Steve

Top-posted from my Windows phone

From: Guido van Rossum
Sent: Saturday, April 21, 2018 19:09
To: Steven D'Aprano
Cc: Python-Dev
Subject: Re: [Python-Dev] PEP 572: Assignment Expressions

On Sat, Apr 21, 2018 at 6:13 PM, Steven D'Aprano  wrote:
On Sat, Apr 21, 2018 at 08:35:51PM +0100, Matthew Woodcraft wrote:

> Well, that's a reason to make the example a bit more realistic, then.
> 
> Say:
> 
> if match := re.search(pat1, text):
>     do_something_with(match.group(0))
> elif match := re.search(pat2, text):
>     do_something_else_with(match.group(0), match.group(1))
> elif match := re.search(pat3, text):
>     do_some_other_things_with(match.group(0))
>     and_also_with(match.group(1), match.group(2))

I don't think that a bunch of generic "do_something_with" functions is 
precisely "realistic".

If I saw something like that, I'd try very hard to find a way to 
refactor it into code like this:

for handler in handlers:
    if handler.match(text):
        handler.process()
        break
else:
    # handle no-match case here

where the knowledge of what to search for, where to search for it, how 
to search for it, and what to do when found, was encapsulated in the 
handler objects. Your tastes may vary.

But your point is well-taken that the version with binding assignment 
(thanks Tim!) is nicer to read than the current procedural version:

match = re.search(pat1, text)
if match:
    do_something_with(match.group(0))
else:
    match = re.search(pat2, text)
    if match:
        do_something_else_with(match.group(0), match.group(1))
    else:
        match = = re.search(pat3, text)
        do_some_other_things_with(match.group(0))
        and_also_with(match.group(1), match.group(2))

I just don't think it counts as a motivating use-case distinct from the 
single match case.

The version of this code found in reality is not as regular as the example 
quoted, and the rebuttal "but I would rewrite it with a loop" shoots a straw 
man. To me the if-elif-elif portion of the example is very much a separate 
motivation, since being able to put the assignment in the elif clause avoids 
runaway indentation. I've regretted not being able to use elif in this kind of 
situation many times, whereas in the single match case I don't find it a burden 
to assign the variable in a separate statement preceding the if-clause. (I 
guess this is a case of "flat is better than nested" -- thanks Tim! :-)


-- 
--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] PEP 572: Assignment Expressions

2018-04-22 Thread Chris Angelico
On Mon, Apr 23, 2018 at 6:22 AM, Mike Miller  wrote:
> On 2018-04-22 12:37, Chris Angelico wrote:
>> Kinda, except that that's not quite a match either. But mainly, the
>> comparison with 'with' and 'except' is dangerously incompatible.
>
> Hmm, looks very close conceptually, though mechanics are different.
>
> Dangerous feels like an exaggeration however.  I've made the argument that
> occurrences would be very rare, but if I'm wrong, the code should blow up on
> its first run.  Perhaps a sanity check could be put in?

with open(fn) as f:
with (open(fn) as f):

These two do the same thing, but only because a file object's
__enter__ returns self. So it's dangerous, because it WILL work... and
people will get into the habit of parenthesizing to permit a 'with'
statement to go across line breaks. And then they'll use a different
context manager, like closing(), or a PsycoPG2 database connection (I
think), where it returns something else. And it'll work, until they go
over multiple lines, and then suddenly the semantics change. It's as
bad as writing JavaScript code like this:

function f(x) {
return x
+ 1;
}

and then transforming it to this:

function f(x) {
return
x + 1;
}

and having it change in behaviour. (Yes, it happens. Welcome to
JavaScript, where implicit semicolons are a thing.)

>> Intuitive consistency isn't enough to handle complex cases.
>> Programming languages that favour intuitive consistency end up with a
>> million special cases.
>
> Ok, but I think we have all the tools we need here, there's just an extra
> place to stub your toe out in the weeds.
>
> To turn the question around, are we really worried that this awkward code
> (or some variant) is about to be written?
>
> with (cm_obj := callable()) as enter_result_obj:
> cm_obj.write()  #  AttributeError
>
> If not, I argue it is a theoretical problem that, if hit, blows up
> immediately.

Were it to blow up immediately, I wouldn't be too bothered.

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: Assignment Expressions

2018-04-22 Thread Mike Miller

On 2018-04-22 12:37, Chris Angelico wrote:
> Kinda, except that that's not quite a match either. But mainly, the
> comparison with 'with' and 'except' is dangerously incompatible.

Hmm, looks very close conceptually, though mechanics are different.

Dangerous feels like an exaggeration however.  I've made the argument that 
occurrences would be very rare, but if I'm wrong, the code should blow up on its 
first run.  Perhaps a sanity check could be put in?


There is a section of your PEP that argues against the "bad code could 
potentially be written" argument, and think it applies here.



> Maybe not, but why not just use ':=' to avoid that?

Don't hate it but feels like Pascal and C and not "Pythonic."  Too many colons, 
avoiding the questions about the difference between "=" and ":=".  Expression 
first is another win.  People know how to use "as".


> Intuitive consistency isn't enough to handle complex cases.
> Programming languages that favour intuitive consistency end up with a
> million special cases.

Ok, but I think we have all the tools we need here, there's just an extra place 
to stub your toe out in the weeds.


To turn the question around, are we really worried that this awkward code (or 
some variant) is about to be written?


with (cm_obj := callable()) as enter_result_obj:
cm_obj.write()  #  AttributeError

If not, I argue it is a theoretical problem that, if hit, blows up immediately.

-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] PEP 572: Assignment Expressions

2018-04-22 Thread Mike Miller


On 2018-04-21 19:57, Chris Angelico wrote:

Thanks for being patient.

Looks like the crux of the issue is that "with … as" binds the result of the 
enter function rather than the context-manager object, as it might first appear. 
Therefore it's not compatible with how "as" is used for direct name bindings 
after "import" statements or this sub-proposal.  Additionally, "except Class as 
instance" names the instance rather than the class.


So, the "as" keyword is already operating at an intuitive level rather than 
idealistic perfection.  Three different semantics for import/with/except, 
correct?  This sub-proposal lines up with the import use, I believe.


Given that there are no use cases for using assignment-expressions in the 
import/with/except statements, and it could be documented that if one insists an 
extra set of parens could make it work:


with (callable() as cm_obj) as enter_result_obj:
pass

It doesn't feel like this issue should be a blocker.

TL;DR - Been feebly trying to make the argument that everyday "intuitive 
consistency" (where the expression will be used) is more important than avoiding 
theoretical problems.  I've never seen complex with/except statements in the 
wild and don't expect this feature to significantly alter that.


-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] PEP 572: Assignment Expressions

2018-04-22 Thread Kirill Balunov
2018-04-22 14:10 GMT+03:00 Kirill Balunov :

>
> Although one of the prerequisites for writing this PEP was the use of the
> assignment expression in the lists
>

Sorry, typo: in compehensions/generators.


> it will rarely be used in them, and even more rarely it will be a
> justified usage of.
>

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


  1   2   3   >