Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Greg Ewing

Nick Coghlan wrote:

I'd be +0 on an "is=" spelling


But "is=' looks like some kind of comparison
operator. This seems even more conusing to me.

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

2018-04-24 Thread Mike Miller


On 2018-04-24 21:05, Nathaniel Smith wrote:

On Tue, Apr 24, 2018 at 8:56 PM, Tim Peters  wrote:

It would actually be quite convenient, and far less error-prone, to
add a binding construct inside a complicated expression for purposes
of running under a debugger.  The alternative is typing the


A bit like breaking complicated expressions into several lines, with or without 
assignments for readability.  ;-)



I thought this was what q was for :-)

https://pypi.org/project/q/


Where have you been all my life, q?

-Mike


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 03:54:30PM -0700, Guido van Rossum wrote:

> We should really take this back to python-ideas at this point.

Please no :-(

Variants of "let" etc were discussed earlier and didn't seem to get much 
interest. Although I don't think "var" specifically was suggested 
before, "let" certainly has been:

https://mail.python.org/pipermail/python-ideas/2018-February/049031.html

In the same thread, I also independently suggested "let":

https://mail.python.org/pipermail/python-ideas/2018-February/048981.html

This suggestion didn't seem to get much in the way of support, so much 
so that in the hundreds of emails for PEP 572 the idea seems to have 
been completely forgotten until now. Perhaps it ought to be added to the 
PEP in the rejected syntax section.

I don't think there's anything to gain by rehashing this again: whether 
we choose "let", "var" or "bind", there's no real difference. It's still 
a new keyword, and it still looks like little else in Python today:

while (var spam = expression) and spam in values:
...

It's not really awful, but nor is it clearly better than := and the fact 
that it will require a keyword is a major point against it.

I'm speaking for myself, of course, not Chris, but while consensus is of 
course desirable I think there comes a time where the PEP author is 
entitled to say "I've heard enough arguments, and I'm not convinced by 
them, this is my proposal and here it stays". If it were my PEP, at this 
point I would say that if anyone wants to champion an alternative syntax 
they can write their own PEP :-)

I think this idea is going to be too divisive to expect a consensus to 
emerge, rather like the ternary if operator. I truly believe we've 
covered just about everything that needs covering, over many hundreds of 
emails in multiple threads, and unless somebody puts their hand up to 
write a competing PEP (or at least says something new beyond what we've 
already seen many times before) I think it is just about time for a BDFL 
decision between:

1. Reject the PEP. Not going to happen.

2. Leave the PEP pending. Maybe some time in the future.

3. Accept the PEP using the `name := expression` syntax.

My preference would be for 3, even though := isn't my first choice for 
syntax, it's still a good choice. I think there are sufficient use-cases 
to justify this feature, including some long standing annoyances such as 
the dance we have to play with regexes, which only gets more annoying as 
you add more alternatives and cascading indentation.

mo = re.match(pattern1, string)
if mo:
process(mo)
else:
   mo = re.match(pattern2, string)
   if mo:
handle(mo)
   else:
   mo = ... # you get the picture


(I've changed my mind from earlier when I said this didn't count as a 
separate use-case from those already given. I think that cascading 
regexes is a big enough pain that it should be explicitly listed in the 
PEP as a motivation.)


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

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

Yes, I'm still reading... but I use pdb approximately zero percent of
the time, so I actually have no idea what's useful for single-stepping
through Python code. So I'm going to write 'blind' here for a bit; do
you reckon this sounds reasonably accurate?

-- existing 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.  Merely introducing a way to assign as an expression
would create bizarre edge cases around comprehensions, though, and to avoid
the worst of the confusions, we change the definition of comprehensions,
causing some edge cases to be interpreted differently, but maintaining the
existing behaviour in the majority of situations.
-- end existing rationale, begin new text --

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 a student or junior programmer.
-- end --

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 572: Write vs Read, Understand and Control Flow

2018-04-24 Thread Nathaniel Smith
On Tue, Apr 24, 2018 at 8:56 PM, Tim Peters  wrote:
> It would actually be quite convenient, and far less error-prone, to
> add a binding construct inside a complicated expression for purposes
> of running under a debugger.  The alternative is typing the
> sub-expression(s) of interest by hand at the debugger prompt, or
> adding print()s, both of which are prone to introducing typos, or
> changing results radically due to triggering side effects in the code
> invoked by the duplicated sub-expression(s).  Adding a binding
> construct wouldn't change anything about how the code worked (apart
> from possibly clobbering a local name).

I thought this was what q was for :-)

https://pypi.org/project/q/

-n

-- 
Nathaniel J. Smith -- https://vorpus.org
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 572: Write vs Read, Understand and Control Flow

2018-04-24 Thread Tim Peters
[Tim]
>> Binding expressions are debugger-friendly in that they _don't_ just
>> vanish without a trace.  It's their purpose to _capture_ the values of
>> the expressions they name.  Indeed, you may want to add them all over
>> the place inside expressions, never intending to use the names, just
>> so that you can see otherwise-ephemeral intra-expression results in
>> your debugger ;-)


[Steven D'Aprano ]
 wrote:
> That's a fantastic point and I'm surprised nobody has thought of it
> until now (that I've seen).
>
> Chris, if you're still reading this and aren't yet heartedly sick and
> tired of the PEP *wink* this ought to go in as another motivating point.

You know, I thought I was joking when I wrote that - but after I sent
it I realized I wasn't ;-)

It would actually be quite convenient, and far less error-prone, to
add a binding construct inside a complicated expression for purposes
of running under a debugger.  The alternative is typing the
sub-expression(s) of interest by hand at the debugger prompt, or
adding print()s, both of which are prone to introducing typos, or
changing results radically due to triggering side effects in the code
invoked by the duplicated sub-expression(s).  Adding a binding
construct wouldn't change anything about how the code worked (apart
from possibly clobbering a local 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-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: Write vs Read, Understand and Control Flow

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 08:10:49PM -0500, Tim Peters wrote:

> Binding expressions are debugger-friendly in that they _don't_ just
> vanish without a trace.  It's their purpose to _capture_ the values of
> the expressions they name.  Indeed, you may want to add them all over
> the place inside expressions, never intending to use the names, just
> so that you can see otherwise-ephemeral intra-expression results in
> your debugger ;-)

That's a fantastic point and I'm surprised nobody has thought of it 
until now (that I've seen).

Chris, if you're still reading this and aren't yet heartedly sick and 
tired of the PEP *wink* this ought to go in as another motivating point.



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

2018-04-24 Thread Dan Stromberg
On Tue, Apr 24, 2018 at 2:21 AM, Victor Stinner  wrote:
> == Write code for babies! ==
>
> Please don't write code for yourself, but write code for babies! :-)
> These babies are going to maintain your code for the next 5 years,
> while you moved to a different team or project in the meanwhile. Be
> kind with your coworkers and juniors!

I don't like the idea of assignment expressions in Python.

“Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.”

- Brian Kernighan

Of the proposed syntaxes, I dislike identifer := expression less, but
I'd still rather not see it added.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 572: Write vs Read, Understand and Control Flow

2018-04-24 Thread Tim Peters
[Victor Stinner]
...
> Tim Peter gaves the following example. "LONG" version:
>
> diff = x - x_base
> if diff:
> g = gcd(diff, n)
> if g > 1:
>return g
>
> versus the "SHORT" version:
>
> if (diff := x - x_base) and (g := gcd(diff, n)) > 1:
>return g
>
> == Write ==
>
> If your job is to write code: the SHORT version can be preferred since
> it's closer to what you have in mind and the code is shorter. When you
> read your own code, it seems straightforward and you like to see
> everything on the same line.

All so, but a bit more:  in context, this is just one block in a
complex algorithm.  The amount of _vertical_ screen space it consumes
directly affects how much of what comes before and after it can be
seen without scrolling.  Understanding this one block in isolation is
approximately useless unless you can also see how it fits into the
whole.  Saving 3 lines of 5 is substantial, but it's more often saving
1 of 5 or 6.  Regardless, they add up.


> The LONG version looks like your expressiveness is limited by the
> computer. It's like having to use simple words when you talk to a
> child, because a child is unable to understand more subtle and
> advanced sentences. You want to write beautiful code for adults,
> right?

I want _the whole_ to be as transparent as possible.  That's a
complicated balancing act in practice.


> == Read and Understand ==
>
> In my professional experience, I spent most of my time on reading
> code, rather than writing code. By reading, I mean: try to understand
> why this specific bug that cannot occur... is always reproduced by the
> customer, whereas we fail to reproduce it in our test lab :-) This bug
> is impossible, you know it, right?
>
> So let's say that you never read the example before, and it has a bug.

Then you're screwed - pay me to fix it ;-)  Seriously, as above, this
block on its own is senseless without understanding both the
mathematics behind what it's doing, and on how all the code before it
picked `x` and `x_base` to begin with.


> By "reading the code", I really mean understanding here. In your
> opinion, which version is easier to *understand*, without actually
> running the code?

Honestly, I find the shorter version a bit easier to understand:
fewer indentation levels, and less semantically empty repetition of
names.


> IMHO the LONG version is simpler to understand, since the code is
> straightforward, it's easy to "guess" the *control flow* (guess in
> which order instructions will be executed).

You're saying you don't know that in "x and y" Python evaluates x
first, and only evaluates y if x "is truthy"?  Sorry, but this seems
trivial to me in either spelling.


> Print the code on paper and try to draw lines to follow the control
> flow. It may be easier to understand how SHORT is more complex to
> understand than LONG.

Since they're semantically identical, there's _something_ suspect
about a conclusion that one is _necessarily_ harder to understand than
the other ;-)  I don't have a problem with you finding the longer
version easier to understand, but I do have a problem if you have a
problem with me finding the shorter easier.


> == Debug ==
>
> Now let's imagine that you can run the code (someone succeeded to
> reproduce the bug in the test lab!). Since it has a bug, you now
> likely want to try to understand why the bug occurs using a debugger.
>
> Sadly, most debugger are designed as if a single line of code can only
> execute a single instruction. I tried pdb: you cannot only run (diff
> := x - x_base) and then get "diff" value, before running the second
> assingment, you can only execute the *full line* at once.
>
> I would say that the LONG version is easier to debug, at least using pdb.

That might be a good reason to avoid, say, list comprehensions (highly
complex expressions of just about any kind), but I think this
overlooks the primary _point_ of "binding expressions":  to give names
to intermediate results.  I couldn't care less if pdb executes the
whole "if" statement in one gulp, because I get exactly the same info
either way:  the names `diff` and `g` bound to the results of the
expressions they named.  What actual difference does it make whether
pdb binds the names one at a time, or both, before it returns to the
prompt?

Binding expressions are debugger-friendly in that they _don't_ just
vanish without a trace.  It's their purpose to _capture_ the values of
the expressions they name.  Indeed, you may want to add them all over
the place inside expressions, never intending to use the names, just
so that you can see otherwise-ephemeral intra-expression results in
your debugger ;-)


> ... Think about tracebacks. If you get an xception at "line 1" in the
> SHORT example (the long "if" expression), what can you deduce
> from the line number? What happened?
>
> If you get an exception in the LONG example, the line number gives you
> a little bit more information... maybe just enough to understand the
> bug?


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread MRAB

On 2018-04-24 23:32, Cameron Simpson wrote:

On 24Apr2018 08:51, Ethan Furman  wrote:

When I compare to variables from outer scopes they *usually* are on
the *right* side of '=='.


You mean something like

 if 2 == x:

?  I never write code like that, and I haven't seen it, either.


Just to this, I also never write code like that but I've certainly seen it
advocated.

I think the rationale was that it places the comparison value foremost in one's
mind, versus the name being tested. I'm not persuaded, but it is another
subjective situation.

It's sometimes advocated in C/C++ code to help catch the inadvertent use 
of = instead of ==, but that's not a problem in Python.

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Cameron Simpson

On 24Apr2018 08:51, Ethan Furman  wrote:

When I compare to variables from outer scopes they *usually* are on
the *right* side of '=='.


You mean something like

 if 2 == x:

?  I never write code like that, and I haven't seen it, either.


Just to this, I also never write code like that but I've certainly seen it 
advocated.


I think the rationale was that it places the comparison value foremost in one's 
mind, versus the name being tested. I'm not persuaded, but it is another 
subjective situation.


Cheers,
Cameron Simpson 
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 10:29:11PM +0100, Anthony Flury via Python-Dev wrote:

> If Python is going to do assignment expressions we shouldn't overload 
> parens in my opinion - we should have a separate operator - doing this 
> avoids needing to exclude rebinding, and makes such expressions 
> considerably more useful.

Exactly!

Yury's suggestion to prohibit rebinding existing names is throwing away 
the baby with the bathwater. Using assignment-expression to over-write 
an existing variable is only a error when it is a mistake, done by 
accident.

To satisfy the compiler, we have to invent new and unique names for what 
is conceptually the same variable being reused. Instead of simplifying 
your code, it will make it more complex.

Despite his statement that there's only one assignment, there are 
actually two: assignment that allows rebinding, and assignment that 
sometimes doesn't. The semantic differences between Yury's = and = are 
actually *greater* than the differences between = and :=


-- 
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 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] assignment expressions: an alternative alternative proposal

2018-04-24 Thread Guido van Rossum
We should really take this back to python-ideas at this point.

On Tue, Apr 24, 2018 at 3:16 PM, Antoine Pitrou  wrote:

> On Tue, 24 Apr 2018 09:38:33 -0400
> Yury Selivanov  wrote:
> > I propose to use the following syntax for assignment expressions:
> >
> > ( NAME = expr )
> >
> > I know that it was proposed before and this idea was rejected, because
> > accidentally using '=' in place of '==' is a pain point in
> > C/C++/JavaScript.
>
> To solve this issue, I would suggest another syntax:
>
> var NAME = expr
>
> Strong points:
> - the "var" keyword makes it clear that it's not a mistyped equality
>   ("var NAME == expr" would be a syntax error)
> - the "var" keyword can stand out thanks to syntax highlighting
> - the "=" which traditionally spells assignement is there as well
>
> Weak points:
> - we need a deprecation cycle before "var" can be used as a keyword
>
> (alternative keyword choices against "var": "using", "let", "bind"...)
>
> 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/
> 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] assignment expressions: an alternative alternative proposal

2018-04-24 Thread Antoine Pitrou
On Tue, 24 Apr 2018 09:38:33 -0400
Yury Selivanov  wrote:
> I propose to use the following syntax for assignment expressions:
> 
> ( NAME = expr )
> 
> I know that it was proposed before and this idea was rejected, because
> accidentally using '=' in place of '==' is a pain point in
> C/C++/JavaScript.

To solve this issue, I would suggest another syntax:

var NAME = expr

Strong points:
- the "var" keyword makes it clear that it's not a mistyped equality
  ("var NAME == expr" would be a syntax error)
- the "var" keyword can stand out thanks to syntax highlighting
- the "=" which traditionally spells assignement is there as well

Weak points:
- we need a deprecation cycle before "var" can be used as a keyword

(alternative keyword choices against "var": "using", "let", "bind"...)

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] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 7:29 AM, Anthony Flury via Python-Dev
 wrote:
> On 24/04/18 17:11, Yury Selivanov wrote:
>>
>> On Tue, Apr 24, 2018 at 12:03 PM, Ethan Furman  wrote:
>> [..]
>>>
>>> But I do write this:
>>>
>>>def wrapper(func, some_value):
>>>  value_I_want = process(some_value)
>>>  def wrapped(*args, **kwds):
>>>if value_I_want == 42:
>>>   ...
>>
>> But this pattern is more rare than comparing local variables. That's
>> the point I'm trying to use.  Besides, to make it an assignment
>> expression under my proposal you would need to use parens. Which makes
>> it even less likely that you confuse '=' and '=='.
>
>
> Just because you wrap a set of character in parens doesn't mean that you
> wont potentially mistype what you should type inside the parens. The failure
> mode of in C :
>
> if (a = 3)
> do_something_with_a(a);
>
> Is Incredibly common even with very experienced developers - so much so that
> most linters flag it as a likely error, and I think gcc has an option to
> flag it as a warning - even though it is valid and very occasionally it is
> useful.

Technically what you have there trips *two* dodgy conditions, and
could produce either warning or both:

1) Potential assignment where you meant comparison
2) Condition is always true.

The combination makes it extremely likely that this wasn't intended.
It's more dangerous, though, when the RHS is a function call...

> Also many developers who come to Python from languages such as C will still
> place parens around conditionals - this means that a typo which will cause a
> Syntax Error in current versions, but would cause a potentially subtle bug
> under your implementation (unless you maintain the rule that you can't
> rebind currently bound names - which renders the whole idea useless in loops
> (as already discussed at length).

Yuri, look how many of the python-dev readers have completely
misinterpreted this "can't rebind" rule. I think that's a fairly clear
indication that the rule is not going to be well understood by anyone
who isn't extremely familiar with the way the language is parsed. I
hesitate to say outright that it is a *bad rule*, but that's the lines
I'm thinking along.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Anthony Flury via Python-Dev

On 24/04/18 17:11, Yury Selivanov wrote:

On Tue, Apr 24, 2018 at 12:03 PM, Ethan Furman  wrote:
[..]

But I do write this:

   def wrapper(func, some_value):
 value_I_want = process(some_value)
 def wrapped(*args, **kwds):
   if value_I_want == 42:
  ...

But this pattern is more rare than comparing local variables. That's
the point I'm trying to use.  Besides, to make it an assignment
expression under my proposal you would need to use parens. Which makes
it even less likely that you confuse '=' and '=='.


Just because you wrap a set of character in parens doesn't mean that you 
wont potentially mistype what you should type inside the parens. The 
failure mode of in C :


    if (a = 3)
        do_something_with_a(a);

Is Incredibly common even with very experienced developers - so much so 
that most linters flag it as a likely error, and I think gcc has an 
option to flag it as a warning - even though it is valid and very 
occasionally it is useful.


Also many developers who come to Python from languages such as C will 
still place parens around conditionals - this means that a typo which 
will cause a Syntax Error in current versions, but would cause a 
potentially subtle bug under your implementation (unless you maintain 
the rule that you can't rebind currently bound names - which renders the 
whole idea useless in loops (as already discussed at length).


I also still can't think of a single other Python construct where the 
semantics of an operator are explicitly modified by syntaxtic elements 
outside the operator. For mathematical operators, the surrounding parens 
modifies the grouping of the operators but not the semantics (* means *, 
it is just the operands which potentially change).


You could argue that your proposal overloads the semantics of the parens 
(similar to how braces are overloaded to implement dictionaries and set 
literals), but I don't think that overloading the semantics of parens is 
good idea.


If Python is going to do assignment expressions we shouldn't overload 
parens in my opinion - we should have a separate operator - doing this 
avoids needing to exclude rebinding, and makes such expressions 
considerably more useful.


--
Anthony Flury
email : *anthony.fl...@btinternet.com*
Twitter : *@TonyFlury *

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 572: Write vs Read, Understand and Control Flow

2018-04-24 Thread Ethan Furman

On 04/24/2018 02:21 AM, Victor Stinner wrote:


WARNING! I was (strongly) opposed to PEP 448 Unpacking Generalizations
(ex: [1, 2, *list]) and PEP 498 f-string (f"Hello {name}"), whereas I
am now a happy user of these new syntaxes. So I'm not sure that I have
good tastes :-)


Cool, you're against PEP 572!  That means you'll end up liking it!!  ;)

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

2018-04-24 Thread Mike Miller


On 2018-04-24 02:21, Victor Stinner wrote:
> I have been asked to express myself on the PEP 572. I'm not sure that


Thanks.  Well written and I've had the same thoughts myself.

___
Python-Dev mailing list
Python-Dev@python.org
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] assignment expressions: an alternative proposal

2018-04-24 Thread Barry Warsaw
On Apr 24, 2018, at 06:55, Antoine Pitrou  wrote:
> 
> If the ambition is to find a piece of syntax that reads as "binds",
> then we can use a variation on the FLUFL operator: "<->".

FLUFL Override Approved!

-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-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] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 2:57 AM, Steven D'Aprano  wrote:
> On Wed, Apr 25, 2018 at 02:42:08AM +1000, Chris Angelico wrote:
>
>> > from math import *
>> > process(arg, (pi = 1), pi+1)  # allowed
>
>
>> That's not allowed at local scope (at least, it's not allowed at
>> function scope - is there any other "local scope" at which it is
>> allowed?).
>
> Of course: local just means the current scope, wherever you happen to
> be. Inside a function, local is the current function scope. Inside a
> class body, local is the class body scope. At the top level of the
> module, local means the module scope (and locals() returns the same dict
> as globals()).
>
> If Yury means for this "cannot mask existing variables" to only operate
> inside functions, that means that you can mask existing variables if you
> use assignment expressions in class bodies or top-level module code.

I don't have a quote for it, but I was under the impression that this
shielding was indeed function-scope-only.

Actually, now that I think about it, I'm not sure whether Yuri's plan
for assignment expressions even included module scope.

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 575: Unifying function/method classes

2018-04-24 Thread Jeroen Demeyer

On 2018-04-20 12:02, Jeroen Demeyer wrote:

One solution to improve backwards compatibility would be to duplicate
some classes. For example, make a separate class for bound methods in
extension types, which would be literally a duplicate of the existing
types.MethodType class (possibly with a different name). In other words,
a bound method of an extension type would work exactly the same way as
an existing bound method but it would artificially be a different class
for the benefit of non-duck-typing.


I elaborated on this:

https://www.python.org/dev/peps/pep-0575/#two-phase-implementation
___
Python-Dev mailing list
Python-Dev@python.org
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 573 -- Module State Access from C Extension Methods

2018-04-24 Thread Jeroen Demeyer

On 2018-04-24 16:34, Jeroen Demeyer wrote:

On the other hand, if you are passing the function object, then you can
get __self__ from it (unless it's an unbound method: in that case
__self__ is NULL and self is really args[0]). So there wouldn't be a
need for passing "self". I'm not saying that this is better than passing
"self" explicitly... I haven't yet decided what is best.


One thing I realized from PEP 573: the fact that __self__ for built-in 
functions is set to the module is considered a feature. I never 
understood the reason for it (and I don't know if the original reason 
was the same as the reason in PEP 573).


If we want to continue supporting that and we also want to support 
__get__ for built-in functions (to make them act as methods), then there 
are really two "selfs": there is the "self" from the method (the object 
that it's bound to) and the "self" from the built-in function (the 
module). To support that, passing *both* the function and "self" seems 
like the best way.



Jeroen.
___
Python-Dev mailing list
Python-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: Write vs Read, Understand and Control Flow

2018-04-24 Thread Victor Stinner
Hi,

I have been asked to express myself on the PEP 572. I'm not sure that
it's useful, but here is my personal opinion on the proposed
"assignment expressions".

PEP 572 -- Assignment Expressions:
https://www.python.org/dev/peps/pep-0572/

First of all, I concur with others: Chris Angelico did a great job to
design a good and full PEP, and a working implementation which is also
useful to play with it!

WARNING! I was (strongly) opposed to PEP 448 Unpacking Generalizations
(ex: [1, 2, *list]) and PEP 498 f-string (f"Hello {name}"), whereas I
am now a happy user of these new syntaxes. So I'm not sure that I have
good tastes :-)


Tim Peter gaves the following example. "LONG" version:

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

versus the "SHORT" version:

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

== Write ==

If your job is to write code: the SHORT version can be preferred since
it's closer to what you have in mind and the code is shorter. When you
read your own code, it seems straightforward and you like to see
everything on the same line.

The LONG version looks like your expressiveness is limited by the
computer. It's like having to use simple words when you talk to a
child, because a child is unable to understand more subtle and
advanced sentences. You want to write beautiful code for adults,
right?

== Read and Understand ==

In my professional experience, I spent most of my time on reading
code, rather than writing code. By reading, I mean: try to understand
why this specific bug that cannot occur... is always reproduced by the
customer, whereas we fail to reproduce it in our test lab :-) This bug
is impossible, you know it, right?

So let's say that you never read the example before, and it has a bug.

By "reading the code", I really mean understanding here. In your
opinion, which version is easier to *understand*, without actually
running the code?

IMHO the LONG version is simpler to understand, since the code is
straightforward, it's easy to "guess" the *control flow* (guess in
which order instructions will be executed).

Print the code on paper and try to draw lines to follow the control
flow. It may be easier to understand how SHORT is more complex to
understand than LONG.

== Debug ==

Now let's imagine that you can run the code (someone succeeded to
reproduce the bug in the test lab!). Since it has a bug, you now
likely want to try to understand why the bug occurs using a debugger.

Sadly, most debugger are designed as if a single line of code can only
execute a single instruction. I tried pdb: you cannot only run (diff
:= x - x_base) and then get "diff" value, before running the second
assingment, you can only execute the *full line* at once.

I would say that the LONG version is easier to debug, at least using pdb.

I'm using regularly gdb which implements the "step" command as I
expect (don't execute the full line, execute sub expressions one by
one), but it's still harder to follow the control flow when a single
line contains multiple instructions, than debugging lines with a
single instruction.

You can see it as a limitation of pdb, but many tools only have the
granularity of whole line. Think about tracebacks. If you get an
exception at "line 1" in the SHORT example (the long "if" expression),
what can you deduce from the line number? What happened?

If you get an exception in the LONG example, the line number gives you
a little bit more information... maybe just enough to understand the
bug?


Example showing the pdb limitation:

>>> def f():
...  breakpoint()
...  if (x:=1) and (y:=2): pass
...
>>> f()
> (3)f()

(Pdb) p x
*** NameError: name 'x' is not defined
(Pdb) p y
*** NameError: name 'y' is not defined

(Pdb) step
--Return--
> (3)f()->None

(Pdb) p x
1
(Pdb) p y
2

... oh, pdb gone too far. I expected a break after "x := 1" and before
"y := 2" :-(


== Write code for babies! ==

Please don't write code for yourself, but write code for babies! :-)
These babies are going to maintain your code for the next 5 years,
while you moved to a different team or project in the meanwhile. Be
kind with your coworkers and juniors!

I'm trying to write a single instruction per line whenever possible,
even if the used language allows me much more complex expressions.
Even if the C language allows assignments in if, I avoid them, because
I regularly have to debug my own code in gdb ;-)

Now the question is which Python are allowed for babies. I recall that
a colleague was surprised and confused by context managers. Does it
mean that try/finally should be preferred? What about f'Hello
{name.title()}' which calls a method into a "string" (formatting)? Or
metaclasses? I guess that the limit should depend on your team, and
may be explained in the coding style designed by your whole team?

Victor
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev

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] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Wed, Apr 25, 2018 at 02:42:08AM +1000, Chris Angelico wrote:

> > from math import *
> > process(arg, (pi = 1), pi+1)  # allowed

 
> That's not allowed at local scope (at least, it's not allowed at
> function scope - is there any other "local scope" at which it is
> allowed?).

Of course: local just means the current scope, wherever you happen to 
be. Inside a function, local is the current function scope. Inside a 
class body, local is the class body scope. At the top level of the 
module, local means the module scope (and locals() returns the same dict 
as globals()).

If Yury means for this "cannot mask existing variables" to only operate 
inside functions, that means that you can mask existing variables if you 
use assignment expressions in class bodies or top-level module code.


-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] 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] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 2:23 AM, Steven D'Aprano  wrote:
> On Tue, Apr 24, 2018 at 11:25:58AM -0400, Yury Selivanov wrote:
>
>> No, it doesn't. The check is performed during compile phase, and
>> Python does not unroll loops. Anyways, read below.
>
> What does unrolling loops have to do with anything? And besides, loop
> unrolling is an implementation detail -- maybe Python will unroll loops,
> maybe it won't.
>
> If you insist that the check is only done at compile time, then your
> description is wrong and your rule that "it is *not* allowed to mask
> names in the current local scope" is false. It *is* allowed to shadow
> names in the local scope, but only names that cannot be determined at
> compile-time.
>
> from math import *
> process(arg, (pi = 1), pi+1)  # allowed
>
> That's more and worse complexity.

That's not allowed at local scope (at least, it's not allowed at
function scope - is there any other "local scope" at which it is
allowed?). Not sure if you can craft equivalent shenanigans with
'exec'.

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 

Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 11:35:20AM -0400, Yury Selivanov wrote:

> Yes, it would force users to come up with better names *iff* they want
> to use this new sugar:
> 
>   if (first_target = get_first_candidate()) ...
>   elif (second_target = get_second_candidate()) ...

They're not better names. Adding "first_" and "second_" prefixes are 
just meaningless waffle added to the name "target" to satisfy the 
compiler so it doesn't complain about reusing the name.

And it is a clear inconsistency with = as a statement and = as an 
expression:

# allowed
target = get_first_candidate()
if target:
...
else:
target = get_second_candidate()
if target: ...


# refactor, and we get a syntax error
if (target = get_first_candidate()):
...
elif (target = get_second_candidate()):
...


And I cannot even begin to guess whether this will be allowed or not:

if (target = get_first_candidate()):
...
while (target = get_second_candidate()):
...


-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 2:28 AM, Steven D'Aprano  wrote:
> On Tue, Apr 24, 2018 at 10:58:24AM -0400, Yury Selivanov wrote:
>
>> Since 'diff' and 'g' must be new names according to rule (3), those
>> who read the code will notice that both were not previously bound.
>
> How am I supposed to notice that they've never been bound without
> carefully reading through the rest of the function in detail, checking
> every single expression and statement?
>
> And besides, you have already established that there are exceptions to
> the rule "names must be new names". For example, in loops.
>
> What other exceptions are there?
>

Yuri is talking about "new" in the syntactic sense. A new name is one
which, reading lexically through the code, has not yet been assigned
to in the function. (I don't know what happens with global/nonlocal
declarations.) Loops have a single point at which the name is assigned
to. This has a single point where the name is assigned, too, even
though you'll never hit it:

def f(x):
if x is not x:
y = 1
print(y) # UnboundLocalError

While I disagree with the proposal, it is at least sane from the
compiler's POV. I don't think it makes sense from a human's POV, but
it's internally consistent.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 11:25:58AM -0400, Yury Selivanov wrote:

> No, it doesn't. The check is performed during compile phase, and
> Python does not unroll loops. Anyways, read below.

What does unrolling loops have to do with anything? And besides, loop 
unrolling is an implementation detail -- maybe Python will unroll loops, 
maybe it won't.

If you insist that the check is only done at compile time, then your 
description is wrong and your rule that "it is *not* allowed to mask 
names in the current local scope" is false. It *is* allowed to shadow 
names in the local scope, but only names that cannot be determined at 
compile-time.

from math import *
process(arg, (pi = 1), pi+1)  # allowed

That's more and worse complexity.

And what about masking names in the class, nonlocal, global and 
builtin scopes? Even more complexity and inconsistent behaviour!

def function():
global a
a = b = 1
process(arg, (a = 2), a+1)  # allowed
process(arg, (b = 2), b+1)  # not allowed



> > I believe that one of the most important use-cases for binding-
> > expression syntax is while loops, like this modified example taken from
> > PEP 572 version 3:
> >
> > while (data = sock.read()):
> > print("Received data:", data)
> >
> > If you prohibit re-binding data, that prohibits cases like this, or even
> > using it inside a loop:
> >
> > for value in sequence:
> > process(arg, (item = expression), item+1)
> 
> No it doesn't. symtable in Python works differently. I encourage you
> to test my reference implementation:
> 
> py> for val in [1, 2, 3]:
> ...   print((item=val), item+1)
> ...
> 1 2
> 2 3
> 3 4

Then your description is false: the assignment in the second time around 
the loop is masking the value that was set the first time around the 
loop. I should be able to unroll the loop by hand, and the code should 
still work:


val = 1
print((item=val), item+1)
val = 2
print((item=val), item+1)
val = 3
print((item=val), item+1)


Does your reference implementation allow that? If not, then you have 
added yet another inconsistency and obscure rule to be learned: using 
assignment expressions will break loop unrolling even if you do it by 
hand.

If it *does* allow that, then so much for your claim that you cannot 
mask existing variables. It can.


> > Why is this allowed?
> >
> > x = 1  # both are statement forms
> > x = 2
> >
> > but this is prohibited?
> >
> > x = 1
> > (x = 2)  # no rebinding is allowed
> >
> > and even more confusing, this is allowed!
> >
> > (x = 1)  # x doesn't exist yet, so it is allowed
> > x = 2  # statement assignment is allowed to rebind
> 
> These all are very limited code snippets that you're unlikely to see
> in real code.

Oh come on now Yury, please be reasonable. They're only *sketches* of 
more realistic code. Of course I'm not actually going to write something 
like 

x = 1
(x = 2)

but do you really need me to take the time and effort to come up with a 
more realistic (and therefore complex) example? Okay.


# allowed
mo = re.match(HEADER_PATTERN, string)
if mo:
process_header(mo)
...  # much later
mo = re.match(FOOTER_PATTERN, string)
if mo:
   process_footer(no)



# not allowed
mo = re.match(HEADER_PATTERN, string)
if mo:
process_header(mo)
...  # much later
if (mo = re.match(FOOTER_PATTERN, string)):  # SyntaxError
   process_footer(no)



You stated that 'There are no "arcane and confusing rules" about "=", 
it's rather simple' but every time we look closely at it, the rules seem 
to get more arcane and confusing.

- why is it okay to mask nonlocal, global, class and builtin
  names, but not local?

- for module-level code, how is the compiler supposed to determine
  the local names in the face of wildcard imports?

- why is it a syntax error to assign to a name which is not
  actually used?

# not allowed
if "a".upper() == "XYZ"[-1].lower():
spam = "this is dead code and will never happen"
process(arg, (spam=expression), spam+1)  # syntax error

# but this is allowed
if "a".upper() == "XYZ"[-1].lower():
spam = "this is dead code and will never happen"
spam = expression
process(arg, spam, spam+1)


- why can you *sometimes* mask existing local variables, if
  they are used in a loop, but not *other* local variables?

- how does this stop *me*, the human reader, from misreading
  (name=expression) as an equality test?



-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 10:58:24AM -0400, Yury Selivanov wrote:

> Since 'diff' and 'g' must be new names according to rule (3), those
> who read the code will notice that both were not previously bound.

How am I supposed to notice that they've never been bound without 
carefully reading through the rest of the function in detail, checking 
every single expression and statement?

And besides, you have already established that there are exceptions to 
the rule "names must be new names". For example, in loops.

What other exceptions are there?


-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 12:03 PM, Ethan Furman  wrote:
[..]
> But I do write this:
>
>   def wrapper(func, some_value):
> value_I_want = process(some_value)
> def wrapped(*args, **kwds):
>   if value_I_want == 42:
>  ...

But this pattern is more rare than comparing local variables. That's
the point I'm trying to use.  Besides, to make it an assignment
expression under my proposal you would need to use parens. Which makes
it even less likely that you confuse '=' and '=='.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:58 AM, Chris Angelico  wrote:
> On Wed, Apr 25, 2018 at 1:49 AM, Yury Selivanov  
> wrote:
>> On Tue, Apr 24, 2018 at 11:34 AM, Steven D'Aprano  
>> wrote:
[..]
>>> There's no advantage to using binding-expressions unless you're going to
>>> re-use the name you just defined, and that re-use will give you a hint
>>> as to what is happening:
>>>
>>> my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
>>
>> Again, this is very subjective, but this code would fail my code review :)
>>
>> Don't you find
>>
>>   buf = [None] * get_size()
>>   my_func(arg, buffer=buf, size=len(buf))
>>
>> to be more readable?
>
> Only if 'buf' is going to be used elsewhere. I'd be looking down below
> for some other use of 'buf'. Technically the same could be true of the
> inline assignment, but it makes more sense for a "this statement only"
> name binding to be within that statement, not broken out and placed
> above it as another operation at equal importance.

Well, you can use empty lines to visually indicate that 'buf' is
related to the call.

Moreover, 'buf' is still available to the code below that code and
sometimes be used there. You can't tell for sure until you glance over
the entire file/function. PEP 572 does not implement any sort of
sub-scoping.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 1:56 AM, Yury Selivanov  wrote:
> On Tue, Apr 24, 2018 at 11:51 AM, Ethan Furman  wrote:
>
>>> When I compare to variables from outer scopes they *usually* are on
>>> the *right* side of '=='.
>>
>>
>> You mean something like
>>
>>   if 2 == x:
>>
>> ?  I never write code like that, and I haven't seen it, either.
>
> Hm. I mean this:
>
>const = 'something'
>
>def foo(arg):
>  if arg == const:
> do something
>
> Note that "const" is on the right side of "==".
>
> Would you write this as
>
>def foo(arg):
>   if const == arg:
>
> ? ;)

That's assuming the global is a constant. What if it's a mode-setting marker?

def foo(arg):
...
if output == "verbose" or (output != "quiet" and error_count):
print("Arg foo'd", arg)
print("Errors found:", error_count)

Then I would definitely put the variable first. And I know a lot of
people who would parenthesize the first condition in this.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Ethan Furman

On 04/24/2018 08:56 AM, Yury Selivanov wrote:

On Tue, Apr 24, 2018 at 11:51 AM, Ethan Furman  wrote:


When I compare to variables from outer scopes they *usually* are on
the *right* side of '=='.



You mean something like

   if 2 == x:

?  I never write code like that, and I haven't seen it, either.


Hm. I mean this:

const = 'something'

def foo(arg):
  if arg == const:
 do something

Note that "const" is on the right side of "==".

Would you write this as

def foo(arg):
   if const == arg:

? ;)


Heh, no.

But I do write this:

  def wrapper(func, some_value):
value_I_want = process(some_value)
def wrapped(*args, **kwds):
  if value_I_want == 42:
 ...

--
~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] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 1:49 AM, Yury Selivanov  wrote:
> On Tue, Apr 24, 2018 at 11:34 AM, Steven D'Aprano  wrote:
>> On Tue, Apr 24, 2018 at 11:05:57AM -0400, Yury Selivanov wrote:
>>
>>> Well, `my_func(a=(b:=foo))` or `my_func(b:=foo)` are also barely
>>> readable to my eye.
>>
>> There's no advantage to using binding-expressions unless you're going to
>> re-use the name you just defined, and that re-use will give you a hint
>> as to what is happening:
>>
>> my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
>
> Again, this is very subjective, but this code would fail my code review :)
>
> Don't you find
>
>   buf = [None] * get_size()
>   my_func(arg, buffer=buf, size=len(buf))
>
> to be more readable?

Only if 'buf' is going to be used elsewhere. I'd be looking down below
for some other use of 'buf'. Technically the same could be true of the
inline assignment, but it makes more sense for a "this statement only"
name binding to be within that statement, not broken out and placed
above it as another operation at equal importance.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:51 AM, Ethan Furman  wrote:

>> When I compare to variables from outer scopes they *usually* are on
>> the *right* side of '=='.
>
>
> You mean something like
>
>   if 2 == x:
>
> ?  I never write code like that, and I haven't seen it, either.

Hm. I mean this:

   const = 'something'

   def foo(arg):
 if arg == const:
do something

Note that "const" is on the right side of "==".

Would you write this as

   def foo(arg):
  if const == arg:

? ;)

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] assignment expressions: an alternative proposal

2018-04-24 Thread Nick Coghlan
On 25 April 2018 at 01:35, Yury Selivanov  wrote:
> On Tue, Apr 24, 2018 at 11:31 AM, Nick Coghlan  wrote:
>> I *do* think the "no name rebinding except in a while loop header"
>> restriction would be annoying for the if/elif use case and the while
>> use case:
>>
>> while (item = get_item()) is not first_delimiter:
>> # First processing loop
>> while (item = get_item()) is not second_delimiter:
>> # Second processing loop
>> # etc...
>>
>> if (target = get_first_candidate()) is not None:
>> ...
>> elif (target = get_second_candidate()) is not None:
>> ...
>> elif (target = get_third_candidate()) is not None:
>> ...
>
> Yes, it would force users to come up with better names *iff* they want
> to use this new sugar:
>
>   if (first_target = get_first_candidate()) ...
>   elif (second_target = get_second_candidate()) ...

Sorry, I didn't make the intended nature of that example clear:

if (target = get_first_candidate()) is not None:
... # Any setup code specific to this kind of target
elif (target = get_second_candidate()) is not None:
... # Any setup code specific to this kind of target
elif (target = get_third_candidate()) is not None:
... # Any setup code specific to this kind of target
else:
raise RuntimeError("No valid candidate found")
# Common code using target goes here

Using a separate name in each branch wouldn't solve the problem of
binding the *same* name for the common code to use later - you'd have
to put a "target = candidate_n" bit of boilerplate in each branch.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:34 AM, Steven D'Aprano  wrote:
> On Tue, Apr 24, 2018 at 11:05:57AM -0400, Yury Selivanov wrote:
>
>> Well, `my_func(a=(b:=foo))` or `my_func(b:=foo)` are also barely
>> readable to my eye.
>
> There's no advantage to using binding-expressions unless you're going to
> re-use the name you just defined, and that re-use will give you a hint
> as to what is happening:
>
> my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))

Again, this is very subjective, but this code would fail my code review :)

Don't you find

  buf = [None] * get_size()
  my_func(arg, buffer=buf, size=len(buf))

to be more readable?

IMHO this example is why we shouldn't implement any form of assignment
expressions in Python :)

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] assignment expressions: an alternative proposal

2018-04-24 Thread Ethan Furman

On 04/24/2018 08:35 AM, Yury Selivanov wrote:


Yes, it would force users to come up with better names *iff* they want
to use this new sugar:

   if (first_target = get_first_candidate()) ...
   elif (second_target = get_second_candidate()) ...


And then the common code below that only cares about a target being found now 
has to do a

  item = first_target or second_target or ...

I don't see that as an improvement.

--
~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] assignment expressions: an alternative proposal

2018-04-24 Thread Ethan Furman

On 04/24/2018 08:19 AM, Yury Selivanov wrote:


Yes, because I'm trying to think about this from a pragmatic side of
things. My question to myself: "what syntax could I use that would
prevent me from making '=' vs '==' mistake when I code?"  To me, the
answer is that I usually want to compare local variables.


I think we need to disambiguate between typo-typos and thinko-typos.  I suspect the vast majority of the '=' bugs are 
not due to the programmer /thinking/ the wrong operation, but of their hands/keyboards not /entering/ the right symbols; 
having a legal operator ("==") degrade into another legal operator ("=") that looks similar but means incredibly 
different things is a trap that we should not add to Python.


You might say that we have the same problems with ">=", "<=", and "!=".  We don't with "!=" because neither "!" nor "=" 
can stand alone and would fail.  We only have it partially with "<=" and ">=" because missing the angle bracket results 
in failure, but missing the "=" results in a working statement -- but that statement is still the same type of operation 
and is easier to debug when boundary cases fail.



When I compare to variables from outer scopes they *usually* are on
the *right* side of '=='.


You mean something like

  if 2 == x:

?  I never write code like that, and I haven't seen it, either.

--
~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] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:28 AM, Chris Angelico  wrote:

> On re-thinking this, I think the distinction IS possible, but (a) only
> in function/class scope, not at global; and (b) would be defined in
> terms of lexical position, not run-time. For instance:
>
> def f():
> (a = 1) # Legal; 'a' has not been used yet
> a = 2 # doesn't change that
>
> def f(a):
> (a = 1) # Invalid - 'a' has been used already
>
> def f():
> while (a = get_next()): # Legal
> ...

Now *this* is a weird rule. Moving functions around files would become
impossible.

Please experiment with my reference implementation, it already
implements my proposal in full. Loops and inline assignments work as
expected in it.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:27 AM, Steven D'Aprano  wrote:
> On Tue, Apr 24, 2018 at 11:03:35AM -0400, Yury Selivanov wrote:
>
>> My point was that when you see lots of '=' and ':=' used at the
>> statement level, one might try to write "if x = 1" instead of "if x :=
>> 1" -- boom, we have an unexpected SyntaxError for some users.
>
> That's a *good* thing. They will then learn not to write x = 1 as an
> expression.
>
> Also, if I write lots of x := 1 binding-expressions as statements, my
> code is bad and deserves to fail code-review. But why would I write the
> extra colon (one character, two key-presses) to use
>
> x := 1
>
> as a statement, when x = 1 will work? That's a sure sign that I don't
> know what I'm doing. (Or that I desperately wish I was writing Pascal.)

In JavaScript there's a new backticks syntax for string—their variant
of f-strings.  I'm seeing a lot of JS coders that use backticks
everywhere, regardless if there's formatting in them or not.  The
result is that some JS code in popular libraries has now *three*
different string literal syntaxes separated by one line of code. It
looks weird. I expect to see something similar in Python code if we
adapt ':='.  I don't think the language will benefit from this.

FWIW I'm fine with keeping the status quo and not adding new syntax at all.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 11:05:57AM -0400, Yury Selivanov wrote:

> Well, `my_func(a=(b:=foo))` or `my_func(b:=foo)` are also barely
> readable to my eye.

There's no advantage to using binding-expressions unless you're going to 
re-use the name you just defined, and that re-use will give you a hint 
as to what is happening:

my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))


> My expectation is that users won't use any form
> of assignment expressions in function calls, it's painful with both
> proposals.

If binding-expressions are accepted into the language, I will certainly 
use them in function calls, *if and when appropriate*. I don't expect it 
will be common, but I'm sure it will happen.



-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 1:15 AM, Steven D'Aprano  wrote:
> By the way, the check for existing variables cannot help to be either
> incomplete or incorrect if you try to do it at compile time:
>
>
> from module import *
> (x = 2)  # allowed or not allowed?
>
>
> If you don't like wild-card imports, how about this:
>
> if random.random() > 0.5:
> spam = 1
> else:
> eggs = 1
> (spam = 2)  # allowed or not? no way to tell at compile time
>
>
> But doing the rebinding/shadowing check at runtime will slow down
> binding expressions, and lead to even more arcane and confusing results:
>
> it = iter("abc")
> while (obj = next(it)):
> print(obj)
>
>
> will print "a" on the first loop, but then raise an exception on
> the second time loop as obj now exists.

On re-thinking this, I think the distinction IS possible, but (a) only
in function/class scope, not at global; and (b) would be defined in
terms of lexical position, not run-time. For instance:

def f():
(a = 1) # Legal; 'a' has not been used yet
a = 2 # doesn't change that

def f(a):
(a = 1) # Invalid - 'a' has been used already

def f():
while (a = get_next()): # Legal
...

This could be handled in the symbol collection pass; if the name
already exists in the function's locals, it's disallowed. But I still
stand by my statement that this creates bizarre cases, and yes, I know
that that word is subjective (just like "readable", "intuitive", and
"sensible"). The rules as given sound like they would make great
linter rules and terrible syntax rules. They are closely aligned with
the OP's experience and usage patterns - which means that, as a
personal linter, they could marvellously assist in catching bugs. You
could have personal (or organization-wide) linter rules disallowing
"class foo:" with a lower-case name, and disallowing the rebinding of
any name in ALL_CAPS, but I would not want either rule codified into
language syntax.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:31 AM, Nick Coghlan  wrote:
> On 25 April 2018 at 00:54, Eric Snow  wrote:
>> Regardless, your 3 rules would benefit either syntax.  Nick may have a
>> point that the rules might be an excessive burden, but I don't think
>> it's too big a deal since the restrictions are few (and align with the
>> most likely usage) and are limited to syntax so the compiler will be
>> quick to point mistakes.
>
> I think the "single name target only" rule should be in place no
> matter the syntax for the name binding operator itself.
>
> I don't mind too much either way on the mandatory parentheses question
> (it's certainly an easy option to actively discourage use of binding
> expressions as a direct alternative to assignment statements, but as
> with the single-name-only rule, it's independent of the choice of
> syntax)

Mandatory parenthesis around `(name := expr)` would at least solve the
problem of users mixing up '=' and ':=' in statements.

>
> I *do* think the "no name rebinding except in a while loop header"
> restriction would be annoying for the if/elif use case and the while
> use case:
>
> while (item = get_item()) is not first_delimiter:
> # First processing loop
> while (item = get_item()) is not second_delimiter:
> # Second processing loop
> # etc...
>
> if (target = get_first_candidate()) is not None:
> ...
> elif (target = get_second_candidate()) is not None:
> ...
> elif (target = get_third_candidate()) is not None:
> ...

Yes, it would force users to come up with better names *iff* they want
to use this new sugar:

  if (first_target = get_first_candidate()) ...
  elif (second_target = get_second_candidate()) ...

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] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 11:03:35AM -0400, Yury Selivanov wrote:

> My point was that when you see lots of '=' and ':=' used at the
> statement level, one might try to write "if x = 1" instead of "if x :=
> 1" -- boom, we have an unexpected SyntaxError for some users.

That's a *good* thing. They will then learn not to write x = 1 as an 
expression.

Also, if I write lots of x := 1 binding-expressions as statements, my 
code is bad and deserves to fail code-review. But why would I write the 
extra colon (one character, two key-presses) to use

x := 1

as a statement, when x = 1 will work? That's a sure sign that I don't 
know what I'm doing. (Or that I desperately wish I was writing Pascal.)

I don't think we need worry about this. The sort of code that is filled 
with binding-expressions used as statements will almost certainly be so 
un-Pythonic and ugly in many other ways, that this won't make any 
difference.


> In my opinion adding *any* assignment expression syntax to Python
> *will* create this sort of issues.  PEP 572 isn't free of them, my
> proposal isn't free of them.  My proposal doesn't add a new ':='
> operator at the cost of slightly complicating rules around '='.  PEP
> 572 avoids complicating '=', but adds an entirely new form of
> assignment.

Indeed. That is true: either way, we introduce complexity into the 
language. (But that will allow us to reduce complexity in *our* code.) 
Given that increasing complexity is inevitable regardless of whether we 
choose PEP 572 or your suggestion, it is better to choose the option 
which keeps binding-expressions and assignment statements separate, 
since they are two different concepts.



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


[Python-Dev] The new and improved PEP 572, same great taste with 75% less complexity!

2018-04-24 Thread Chris Angelico
The most notable change since last posting is that the assignment
target is no longer as flexible as with the statement form of
assignment, but is restricted to a simple name.

Note that the reference implementation has not been updated.

ChrisA


PEP: 572
Title: Assignment Expressions
Author: Chris Angelico 
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


Abstract


This is a proposal for creating a way to assign to variables within an
expression. Additionally, the precise scope of comprehensions is adjusted, to
maintain consistency and follow expectations.


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.  Merely introducing a way to assign as an expression
would create bizarre edge cases around comprehensions, though, and to avoid
the worst of the confusions, we change the definition of comprehensions,
causing some edge cases to be interpreted differently, but maintaining the
existing behaviour in the majority of situations.


Syntax and semantics


In any context where arbitrary Python expressions can be used, a **named
expression** can appear. This is of the form ``name := expr`` where
``expr`` is any valid Python expression, and ``name`` is an identifier.

The value of such a named expression is the same as the incorporated
expression, with the additional side-effect that the target is assigned
that value::

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

# A more explicit alternative to the 2-arg form of iter() invocation
while (value := read_next_item()) is not None:
...

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


Differences from regular assignment statements
--

Most importantly, since ``:=`` is an expression, it can be used in contexts
where statements are illegal, including lambda functions and comprehensions.

An assignment statement can assign to multiple targets, left-to-right::

x = y = z = 0

The equivalent assignment expression is parsed as separate binary operators,
and is therefore processed right-to-left, as if it were spelled thus::

assert 0 == (x := (y := (z := 0)))

Statement assignment can include annotations. This would be syntactically
noisy in expressions, and is of minor importance. An annotation can be
given separately from the assignment if needed::

x:str = "" # works
(x:str := "") # SyntaxError
x:str # possibly before a loop
(x := "") # fine

Augmented assignment is not supported in expression form::

>>> x +:= 1
  File "", line 1
x +:= 1
^
SyntaxError: invalid syntax

Statement assignment is able to set attributes and subscripts, but
expression assignment is restricted to names. (This restriction may be
relaxed in a future version of Python.)

Otherwise, the semantics of assignment are identical in statement and
expression forms.


Alterations to comprehensions
-

The current behaviour of list/set/dict comprehensions and generator
expressions has some edge cases that would behave strangely if an assignment
expression were to be used. Therefore the proposed semantics are changed,
removing the current edge cases, and instead altering their behaviour *only*
in a class scope.

As of Python 3.7, the outermost iterable of any comprehension is evaluated
in the surrounding context, and then passed as an argument to the implicit
function that evaluates the comprehension.

Under this proposal, the entire body of the comprehension is evaluated in
its implicit function. Names not assigned to within the comprehension are
located in the surrounding scopes, as with normal lookups. As one special
case, a comprehension at class scope will **eagerly bind** any name which
is already defined in the class scope.

A list comprehension can be unrolled into an equivalent function. With
Python 3.7 semantics::

numbers = [x + y for x in range(3) for y in range(4)]
# Is approximately equivalent to
def (iterator):
result = []
for x in iterator:
for y in range(4):
result.append(x + y)
return result
numbers = (iter(range(3)))

Under the new semantics, this would instead be equivalent to::

def ():
result = []
for x in range(3):
for y in range(4):
result.append(x + y)
return result
numbers = ()

When a class 

Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:15 AM, Steven D'Aprano  wrote:
[..]

>> >> 3. Most importantly: it is *not* allowed to mask names in the current
>> >> local scope.
>
> That means you can't rebind existing variables. That means you can't
> rebind to the same variable in a loop.

No, it doesn't. The check is performed during compile phase, and
Python does not unroll loops. Anyways, read below.

> I believe that one of the most important use-cases for binding-
> expression syntax is while loops, like this modified example taken from
> PEP 572 version 3:
>
> while (data = sock.read()):
> print("Received data:", data)
>
> If you prohibit re-binding data, that prohibits cases like this, or even
> using it inside a loop:
>
> for value in sequence:
> process(arg, (item = expression), item+1)

No it doesn't. symtable in Python works differently. I encourage you
to test my reference implementation:

py> for val in [1, 2, 3]:
...   print((item=val), item+1)
...
1 2
2 3
3 4

> Why is this allowed?
>
> x = 1  # both are statement forms
> x = 2
>
> but this is prohibited?
>
> x = 1
> (x = 2)  # no rebinding is allowed
>
> and even more confusing, this is allowed!
>
> (x = 1)  # x doesn't exist yet, so it is allowed
> x = 2  # statement assignment is allowed to rebind

These all are very limited code snippets that you're unlikely to see
in real code.  I can write (and I did in this thread) a bunch of
examples of where PEP 572 is also inconsistent.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Nick Coghlan
On 25 April 2018 at 00:54, Eric Snow  wrote:
> Regardless, your 3 rules would benefit either syntax.  Nick may have a
> point that the rules might be an excessive burden, but I don't think
> it's too big a deal since the restrictions are few (and align with the
> most likely usage) and are limited to syntax so the compiler will be
> quick to point mistakes.

I think the "single name target only" rule should be in place no
matter the syntax for the name binding operator itself.

I don't mind too much either way on the mandatory parentheses question
(it's certainly an easy option to actively discourage use of binding
expressions as a direct alternative to assignment statements, but as
with the single-name-only rule, it's independent of the choice of
syntax)

I *do* think the "no name rebinding except in a while loop header"
restriction would be annoying for the if/elif use case and the while
use case:

while (item = get_item()) is not first_delimiter:
# First processing loop
while (item = get_item()) is not second_delimiter:
# Second processing loop
# etc...

if (target = get_first_candidate()) is not None:
...
elif (target = get_second_candidate()) is not None:
...
elif (target = get_third_candidate()) is not None:
...

And *that* rule is unique to the "=" spelling, since for other
proposals "lhs = rhs" in an expression is *always* a syntax error, and
you have to resolve the ambiguity in intent explicitly by either
adding a second "=" (to request equality comparison), or else some
other leading symbol (to request a binding expression).

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


[Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Christoph Groth
Yury Selivanov wrote:
> I propose to use the following syntax for assignment expressions:
>
> ( NAME = expr )

Yury, did you notice the subthread [1] that discusses the merits and
problems of the same idea (except for your point 3)?

[1] https://mail.python.org/pipermail/python-dev/2018-April/152868.html
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 11:07 AM, Chris Angelico  wrote:
[..]

> x = 1
> if (x = 2): ...
>
> This, according to your proposal, raises SyntaxError - not because a
> comparison was wanted and an assignment was made, but because the name
> already had a value. And, even worse, this is NOT an error:

Yes, because I'm trying to think about this from a pragmatic side of
things. My question to myself: "what syntax could I use that would
prevent me from making '=' vs '==' mistake when I code?"  To me, the
answer is that I usually want to compare local variables.

When I compare to variables from outer scopes they *usually* are on
the *right* side of '=='.

>
> x = 1
> def f():
> if (x = 2):
> ...
>
> That's a bizarre distinction.

Chris, FWIW I'm trying to avoid using 'bizarre', 'arcane' etc with
regards to PEP 572 or any proposal, really. For example, I,
personally, find ':=' bizarre, but it's subjective and it's
unproductive to say that.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 09:50:34AM -0400, Yury Selivanov wrote:
> On Tue, Apr 24, 2018 at 9:46 AM, Nick Coghlan  wrote:
> > On 24 April 2018 at 23:38, Yury Selivanov  wrote:
> >> I propose to use the following syntax for assignment expressions:
> >>
> >> ( NAME = expr )
> >>
> >> I know that it was proposed before and this idea was rejected, because
> >> accidentally using '=' in place of '==' is a pain point in
> >> C/C++/JavaScript.
> >>
> >> That said, I believe we can still use this syntax as long as we impose
> >> the following three restrictions on it:
> >>
> >> 1. Only NAME token is allowed as a single target.
> >>
> >> 2. Parenthesis are required.

There are many places where I would use parentheses even if they are 
not required, but being forced to use them when they're not and I don't 
want them is ugly.

I also question why you think this will help prevent accidentally 
writing = when you meant == (equality). Have you never written something 
like this?

if (x == y) or (a > b): ...

Yes, I know the parens are not strictly needed, since the precedence of 
`or` is lower than the comparison operators. But still, especially for 
complex comparisons, a few extra (round) brackets can improve 
readability.

So now we have:

if (x = y) or (a > b): ...  # oops


But the biggest problem with this is that it is ambiguous to the human 
reader. At a glance, I'm likely to read x=y in an expression as 
equality. If I notice that it is a single = sign, I'm never going to be 
sure whether it was a mistake or intentional until I study the rest of 
the function minutely.

The benefit of := is that if I see it, I can be pretty sure it was not a 
typo. It is hard to mistype == as := by accident, and they are visually 
distinct enough that I am not going to misread := as == .


> >> 3. Most importantly: it is *not* allowed to mask names in the current
> >> local scope.

That means you can't rebind existing variables. That means you can't 
rebind to the same variable in a loop.

I believe that one of the most important use-cases for binding- 
expression syntax is while loops, like this modified example taken from 
PEP 572 version 3:

while (data = sock.read()):
print("Received data:", data)

If you prohibit re-binding data, that prohibits cases like this, or even 
using it inside a loop:

for value in sequence:
process(arg, (item = expression), item+1)


Your suggestion to prohibit rebinding variables effectively makes them 
so crippled as to be useless to me.


> > While I agree this would be unambiguous to a computer, I think for
> > most humans it would be experienced as a confusing set of arcane and
> > arbitrary rules about what "=" means in Python.
> 
> I respectfully disagree.  There are no "arcane and confusing rules"
> about "=", it's rather simple:
> 
> "=" is always an assignment.

Why is this allowed?

x = 1  # both are statement forms
x = 2

but this is prohibited?

x = 1
(x = 2)  # no rebinding is allowed

and even more confusing, this is allowed!

(x = 1)  # x doesn't exist yet, so it is allowed
x = 2  # statement assignment is allowed to rebind


By the way, the check for existing variables cannot help to be either 
incomplete or incorrect if you try to do it at compile time:


from module import *
(x = 2)  # allowed or not allowed?


If you don't like wild-card imports, how about this:

if random.random() > 0.5:
spam = 1
else:
eggs = 1
(spam = 2)  # allowed or not? no way to tell at compile time


But doing the rebinding/shadowing check at runtime will slow down 
binding expressions, and lead to even more arcane and confusing results:

it = iter("abc")
while (obj = next(it)):
print(obj)


will print "a" on the first loop, but then raise an exception on 
the second time loop as obj now exists.



-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 12:58 AM, Yury Selivanov
 wrote:
> On Tue, Apr 24, 2018 at 10:49 AM, Paul Moore  wrote:
> [..]
 3. Most importantly: it is *not* allowed to mask names in the current
 local scope.
>>>
>>> While I agree this would be unambiguous to a computer, I think for
>>> most humans it would be experienced as a confusing set of arcane and
>>> arbitrary rules about what "=" means in Python.
>>
>> Also, there's the ambiguity and potential for misreading in the
>> opposite direction (accidentally *reading* = as == even though it
>> isn't):
>>
>> if (diff = x - x_base) and (g = gcd(diff, n)) > 1:
>>  return g
>
> Since 'diff' and 'g' must be new names according to rule (3), those
> who read the code will notice that both were not previously bound.
> Therefore both are new variables so it can't be a comparison.

That would not be true if this code were in a loop. Or do you have a
different definition of "not previously bound" that is actually a
syntactic feature? For instance:

if (x = 1):
x = 2

Legal? Not legal?

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 1:03 AM, Yury Selivanov  wrote:
> On Tue, Apr 24, 2018 at 10:56 AM, Chris Angelico  wrote:
> [..]
>>> A lot of other questions arise though.  PEP 572 proposes:
>>>
>>> a = 1  # assignment
>>> a := 1  # also assignment
>>> (a := 1)  # also assignment
>>> (a = 1)  # error, why?
>>
>> Your third example is just the same as the second, with parentheses
>> around it. In most of Python, parentheses (if legal) have no effect
>> other than grouping; "a + b * c" is the same thing as "(a + b) * c",
>> just done in the other order. The last one is a clear demonstration
>> that "=" is a statement, not an expression. Are people confused by
>> this sort of thing:
>>
>> if x > 1:
>> print("x is more than 1")
>> (if x > 1:)
>> print("SyntaxError")
>
> This is a very far-fetched example :)

Heh, yes it is. But my point is that the parens are not creating a
weird situation here. They're just showcasing a distinction: one of
these is a statement, the other an expression. Which is the entire
point of the different operator - one is a syntactic feature of a
statement that creates one or more name bindings, the other is a
binary operator which results in a name binding as well as a value.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Paul Moore
On 24 April 2018 at 15:58, Yury Selivanov  wrote:
> On Tue, Apr 24, 2018 at 10:49 AM, Paul Moore  wrote:
> [..]
 3. Most importantly: it is *not* allowed to mask names in the current
 local scope.
>>>
>>> While I agree this would be unambiguous to a computer, I think for
>>> most humans it would be experienced as a confusing set of arcane and
>>> arbitrary rules about what "=" means in Python.
>>
>> Also, there's the ambiguity and potential for misreading in the
>> opposite direction (accidentally *reading* = as == even though it
>> isn't):
>>
>> if (diff = x - x_base) and (g = gcd(diff, n)) > 1:
>>  return g
>
> Since 'diff' and 'g' must be new names according to rule (3), those
> who read the code will notice that both were not previously bound.
> Therefore both are new variables so it can't be a comparison.

That was essentially my point, though - I can no longer read that line
of code in isolation from the surrounding context. Consider something
like a github PR review screen, where surrounding unchanged code is
frequently hidden.

Anyway, we can agree to differ on this - I don't like this idea and
I'd personally find it hard to read, but as you've already pointed
out, this is all extremely subjective.
Paul
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 10:54 AM, Anthony Flury via Python-Dev
 wrote:
[..]
> As discussed previously by others on this exact proposals, you now have the
> issue of  confusion when using keyword arguments : *my_func(a = b)* :
> clearly that is a call to `my_func' where argument a has the value of b, but
> if you want to do an assigment expression when calling the function you now
> have to do *my_func((a=b)) -* which frankly looks messy in my opinion; you
> get the same issue when you are wanting to do assignment expressions in
> tuples.

Well, `my_func(a=(b:=foo))` or `my_func(b:=foo)` are also barely
readable to my eye.  My expectation is that users won't use any form
of assignment expressions in function calls, it's painful with both
proposals.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 12:54 AM, Anthony Flury via Python-Dev
 wrote:
> As discussed previously by others on this exact proposals, you now have the
> issue of  confusion when using keyword arguments : *my_func(a = b)* :
> clearly that is a call to `my_func' where argument a has the value of b, but
> if you want to do an assigment expression when calling the function you now
> have to do *my_func((a=b)) -* which frankly looks messy in my opinion; you
> get the same issue when you are wanting to do assignment expressions in
> tuples.

To be fair, function arguments already follow "practicality beats
purity" in many ways. Let's look at tuples:

x = 1, 2 # fine
x = (1, 2) # fine
x = 1, # fine, though not advisable
x = (1,) # fine

But if you're going to use a tuple literal as a function parameter,
you have to give it extra parens:

f((1, 2)) # one arg, a tuple
f(1, 2) # two args

The comma has multiple meanings, and it has to be disambiguated. The
equals sign would be the same.

I'm still strongly -1 on any proposal to have "=" mean assignment in
any expression context, though. It is WAY too easy for a comparison to
sneakily become an assignment, or to get bizarre syntax errors:

x = 1
if (x = 2): ...

This, according to your proposal, raises SyntaxError - not because a
comparison was wanted and an assignment was made, but because the name
already had a value. And, even worse, this is NOT an error:

x = 1
def f():
if (x = 2):
...

That's a bizarre distinction.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 10:49 AM, Paul Moore  wrote:
[..]
>>> 3. Most importantly: it is *not* allowed to mask names in the current
>>> local scope.
>>
>> While I agree this would be unambiguous to a computer, I think for
>> most humans it would be experienced as a confusing set of arcane and
>> arbitrary rules about what "=" means in Python.
>
> Also, there's the ambiguity and potential for misreading in the
> opposite direction (accidentally *reading* = as == even though it
> isn't):
>
> if (diff = x - x_base) and (g = gcd(diff, n)) > 1:
>  return g

Since 'diff' and 'g' must be new names according to rule (3), those
who read the code will notice that both were not previously bound.
Therefore both are new variables so it can't be a comparison.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Eric Snow
Thanks for thinking this through, Yury. :)

FWIW, I'm still unconvinced that an assignment expression is worth it.
It's hard to say, though, without seeing how much folks would actually
use it (and I don't have my own time machine unfortunately).  IIRC, in
the past several proposed syntax (e.g. decorators) were in the same
boat and in retrospect turned out to be a strongly positive addition
to the language. :)

Comments in-line below.

-eric

On Tue, Apr 24, 2018 at 7:38 AM, Yury Selivanov  wrote:
> I propose to use the following syntax for assignment expressions:
>
> ( NAME = expr )
>
> [snip]
>
> 1. Only NAME token is allowed as a single target.

This seems reasonable and does keep assignment expressions easier for
the reader to find.  At the same time, there have been some arguments
elsewhere in favor of tuple unpacking as the other obvious use case.
Presumably that would not be supported under this rule.

> 2. Parenthesis are required.

Similar to rule #1, this would make assignment expressions more
obvious to readers, which is a good thing.

>
> 3. Most importantly: it is *not* allowed to mask names in the current
> local scope.

I was about to leave this counter example for
accidentally-typed-one-equal-sign-instead-of-two bugs:

if (y == 3):
print(y)
# vs.
if (y = 3):
print(y)

Then it dawned on me that your rule #3 solves this. :)

> [snip]
>
> py> f = lambda x: x * 10
> py> [[(y = f(x)), x/y] for x in range(1,5)]
> [[10, 0.1], [20, 0.1], [30, 0.1], [40, 0.1]]
>
> [snip]
>
> I believe that this syntax is the best of both worlds: it allows to
> write succinct code just like PEP 572, but without introducing a new
> ':=' operator.

This is the main point of this alternate proposal, right?  It
certainly seems reasonable that we not add another assignment syntax.
On the other hand, having ":=" as a distinct syntax for assignment
expressions is close enough to the existing syntax that it doesn't
really add any real extra burden to readers, while being more
searchable and visually distinct.  If we were to add assignment
expressions I'd probably favor ":=".

Regardless, your 3 rules would benefit either syntax.  Nick may have a
point that the rules might be an excessive burden, but I don't think
it's too big a deal since the restrictions are few (and align with the
most likely usage) and are limited to syntax so the compiler will be
quick to point mistakes.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 10:56 AM, Chris Angelico  wrote:
[..]
>> A lot of other questions arise though.  PEP 572 proposes:
>>
>> a = 1  # assignment
>> a := 1  # also assignment
>> (a := 1)  # also assignment
>> (a = 1)  # error, why?
>
> Your third example is just the same as the second, with parentheses
> around it. In most of Python, parentheses (if legal) have no effect
> other than grouping; "a + b * c" is the same thing as "(a + b) * c",
> just done in the other order. The last one is a clear demonstration
> that "=" is a statement, not an expression. Are people confused by
> this sort of thing:
>
> if x > 1:
> print("x is more than 1")
> (if x > 1:)
> print("SyntaxError")

This is a very far-fetched example :)

My point was that when you see lots of '=' and ':=' used at the
statement level, one might try to write "if x = 1" instead of "if x :=
1" -- boom, we have an unexpected SyntaxError for some users.

In my opinion adding *any* assignment expression syntax to Python
*will* create this sort of issues.  PEP 572 isn't free of them, my
proposal isn't free of them.  My proposal doesn't add a new ':='
operator at the cost of slightly complicating rules around '='.  PEP
572 avoids complicating '=', but adds an entirely new form of
assignment.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Anthony Flury via Python-Dev

On 24/04/18 14:50, Yury Selivanov wrote:

On Tue, Apr 24, 2018 at 9:46 AM, Nick Coghlan  wrote:

On 24 April 2018 at 23:38, Yury Selivanov  wrote:

I propose to use the following syntax for assignment expressions:

 ( NAME = expr )

I know that it was proposed before and this idea was rejected, because
accidentally using '=' in place of '==' is a pain point in
C/C++/JavaScript.

That said, I believe we can still use this syntax as long as we impose
the following three restrictions on it:

1. Only NAME token is allowed as a single target.

2. Parenthesis are required.

3. Most importantly: it is *not* allowed to mask names in the current
local scope.

While I agree this would be unambiguous to a computer, I think for
most humans it would be experienced as a confusing set of arcane and
arbitrary rules about what "=" means in Python.

I respectfully disagree.  There are no "arcane and confusing rules"
about "=", it's rather simple:

"=" is always an assignment.

But it isn't - in your proposed syntax :

 * * = * is an assignment with no return value
 * *( = )* is an assignment with a returned value

  So now '=' is always an assignment, it is an assignment with extra 
semantics depending on surrounding syntax.


As discussed previously by others on this exact proposals, you now have 
the issue of  confusion when using keyword arguments : *my_func(a = b)* 
: clearly that is a call to `my_func' where argument a has the value of 
b, but if you want to do an assigment expression when calling the 
function you now have to do *my_func((a=b)) -* which frankly looks messy 
in my opinion; you get the same issue when you are wanting to do 
assignment expressions in tuples.


Using a different operator for assignments which return values avoids 
the messy potentially multiple level brackets, and means that the 
semantics of an operator depends only on that operator and not on syntax 
elements before and after it.


--
--
Anthony Flury
email : *anthony.fl...@btinternet.com*
Twitter : *@TonyFlury *

___
Python-Dev mailing list
Python-Dev@python.org
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 573 -- Module State Access from C Extension Methods

2018-04-24 Thread Marcel Plch
If PEP 575's new call doesn't have any surprising restrictions,
I think that completely dropping METH_METHOD would be the
best way of resolving this.
I suggest we push PEP 575 first and if it gets accepted, I will rebase
PEP 573 to these changes.

On Tue, Apr 24, 2018 at 4:34 PM, Jeroen Demeyer  wrote:
> On 2018-04-24 14:53, Nick Coghlan wrote:
>>>
>>> In PEP 575, I'm already proposing a flag (METH_ARG0_FUNCTION) to pass the
>>> function *instead* of self. Unless PEP 573 is rejected, maybe that should
>>> change to passing the function *in addition* to self.
>>
>>
>> That would definitely be an elegant way of addressing both use cases.
>
>
> On the other hand, if you are passing the function object, then you can get
> __self__ from it (unless it's an unbound method: in that case __self__ is
> NULL and self is really args[0]). So there wouldn't be a need for passing
> "self". I'm not saying that this is better than passing "self" explicitly...
> I haven't yet decided what is best.
>
> In any case, these things would be handled by Argument Clinic anyway, so it
> only matters if you are parsing arguments "by hand".
>
>
>
> Jeroen.
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/gmarcel.plch%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] assignment expressions: an alternative proposal

2018-04-24 Thread Chris Angelico
On Wed, Apr 25, 2018 at 12:23 AM, Yury Selivanov
 wrote:
> On Tue, Apr 24, 2018 at 10:07 AM, Nick Coghlan  wrote:
>
>>> "=" is always an assignment.
>>> "==" is always an equality check.
>>
>> That's not the distinction I meant, I meant the difficulty of
>> explaining the discrepancies in this list:
>>
>> a = 1 # Assignment
>> (a = 1) # Also assignment
>>
>> a, b = 1, 2 # Tuple assignment
>> (a, b = 1, 2) # SyntaxError. Why?
>>
>> ...
>> Whereas if binding expressions use a different symbol, the question is
>> far less likely to arise, and if it does come up, then the answer is
>> the same as the one for def statements vs lambda expressions: because
>> one is a statement, and the other is an expression.
>
> A lot of other questions arise though.  PEP 572 proposes:
>
> a = 1  # assignment
> a := 1  # also assignment
> (a := 1)  # also assignment
> (a = 1)  # error, why?

Your third example is just the same as the second, with parentheses
around it. In most of Python, parentheses (if legal) have no effect
other than grouping; "a + b * c" is the same thing as "(a + b) * c",
just done in the other order. The last one is a clear demonstration
that "=" is a statement, not an expression. Are people confused by
this sort of thing:

if x > 1:
print("x is more than 1")
(if x > 1:)
print("SyntaxError")

? Yes, the word 'if' does have meaning in an expression context, and
yes, it has a similar meaning to the 'if' statement, but people don't
parenthesize entire statements. You try that with assignment, you get
an error, and bam, it's obvious that you ran into this particular
case.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Nick Coghlan
On 25 April 2018 at 00:23, Yury Selivanov  wrote:
> A lot of other questions arise though.  PEP 572 proposes:
>
> a = 1  # assignment
> a := 1  # also assignment
> (a := 1)  # also assignment
> (a = 1)  # error, why?

That's just the typical assignment/expression dichotomy, though, which
is genuinely confusing for learners (since expression-level Python and
statement-level Python allow different constructs), but also not a new
problem.

All the other keywords that have both statement level and expression
level use cases are structured as prefix operators in statement form,
and some kind of infix operator in expression form, whereas this would
be the first case where we offered a construct that used infix syntax
for both its statement form and its expression form.

> It's also difficult to explain which one to use when.  The net result
> is that code will be littered with both at random places.  That will
> decrease the readability of Python code at least for some users who
> have similar taste to myself.

That's a legitimate concern with PEP 572 (and part of why I'm
somewhere between -1 and -0 on the ":=" spelling, although I'd be +0
on an "is=" spelling that riffs off the "is" comparison operator -
using the "name is= expr" spelling in place of a regular assignment
looks sufficiently odd that I'd expect the temptation to write it in
place of "name = expr" when the latter is permitted would be low)

> With '=' in expressions, the code will look uniform.  There will be a
> simple rule to put parens around assignments in expression and use
> simple names.  After one or two descriptive SyntaxError users will
> learn how this syntax works (like people learn everything in coding).

Except that they'll also find other discrepancies like:

a = 1
a = 2

being OK, while:

a = 1
(a = 2)

fails with SyntaxError on the second line.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Paul Moore
On 24 April 2018 at 14:46, Nick Coghlan  wrote:
> On 24 April 2018 at 23:38, Yury Selivanov  wrote:
>> I propose to use the following syntax for assignment expressions:
>>
>> ( NAME = expr )
>>
>> I know that it was proposed before and this idea was rejected, because
>> accidentally using '=' in place of '==' is a pain point in
>> C/C++/JavaScript.
>>
>> That said, I believe we can still use this syntax as long as we impose
>> the following three restrictions on it:
>>
>> 1. Only NAME token is allowed as a single target.
>>
>> 2. Parenthesis are required.
>>
>> 3. Most importantly: it is *not* allowed to mask names in the current
>> local scope.
>
> While I agree this would be unambiguous to a computer, I think for
> most humans it would be experienced as a confusing set of arcane and
> arbitrary rules about what "=" means in Python.

Also, there's the ambiguity and potential for misreading in the
opposite direction (accidentally *reading* = as == even though it
isn't):

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

My immediate reading of this is as an equality comparison between diff
and x - x_base (which would send me futilely looking for a definition
of diff) and an equality comparison of g and gcd(diff, n)... wait, why
am I doing (equality comparison) > 1? Oh, hang on... At this point,
any hope of me quickly understanding what this code does is lost.

Paul
___
Python-Dev mailing list
Python-Dev@python.org
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 573 -- Module State Access from C Extension Methods

2018-04-24 Thread Jeroen Demeyer

On 2018-04-24 14:53, Nick Coghlan wrote:

In PEP 575, I'm already proposing a flag (METH_ARG0_FUNCTION) to pass the
function *instead* of self. Unless PEP 573 is rejected, maybe that should
change to passing the function *in addition* to self.


That would definitely be an elegant way of addressing both use cases.


On the other hand, if you are passing the function object, then you can 
get __self__ from it (unless it's an unbound method: in that case 
__self__ is NULL and self is really args[0]). So there wouldn't be a 
need for passing "self". I'm not saying that this is better than passing 
"self" explicitly... I haven't yet decided what is best.


In any case, these things would be handled by Argument Clinic anyway, so 
it only matters if you are parsing arguments "by hand".



Jeroen.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 10:07 AM, Nick Coghlan  wrote:

>> "=" is always an assignment.
>> "==" is always an equality check.
>
> That's not the distinction I meant, I meant the difficulty of
> explaining the discrepancies in this list:
>
> a = 1 # Assignment
> (a = 1) # Also assignment
>
> a, b = 1, 2 # Tuple assignment
> (a, b = 1, 2) # SyntaxError. Why?
>
> ...
> Whereas if binding expressions use a different symbol, the question is
> far less likely to arise, and if it does come up, then the answer is
> the same as the one for def statements vs lambda expressions: because
> one is a statement, and the other is an expression.

A lot of other questions arise though.  PEP 572 proposes:

a = 1  # assignment
a := 1  # also assignment
(a := 1)  # also assignment
(a = 1)  # error, why?

It's also difficult to explain which one to use when.  The net result
is that code will be littered with both at random places.  That will
decrease the readability of Python code at least for some users who
have similar taste to myself.

With '=' in expressions, the code will look uniform.  There will be a
simple rule to put parens around assignments in expression and use
simple names.  After one or two descriptive SyntaxError users will
learn how this syntax works (like people learn everything in coding).

This all is very subjective.

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-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] assignment expressions: an alternative proposal

2018-04-24 Thread Nick Coghlan
On 24 April 2018 at 23:50, Yury Selivanov  wrote:
> On Tue, Apr 24, 2018 at 9:46 AM, Nick Coghlan  wrote:
>> On 24 April 2018 at 23:38, Yury Selivanov  wrote:
>>> I propose to use the following syntax for assignment expressions:
>>>
>>> ( NAME = expr )
>>>
>>> I know that it was proposed before and this idea was rejected, because
>>> accidentally using '=' in place of '==' is a pain point in
>>> C/C++/JavaScript.
>>>
>>> That said, I believe we can still use this syntax as long as we impose
>>> the following three restrictions on it:
>>>
>>> 1. Only NAME token is allowed as a single target.
>>>
>>> 2. Parenthesis are required.
>>>
>>> 3. Most importantly: it is *not* allowed to mask names in the current
>>> local scope.
>>
>> While I agree this would be unambiguous to a computer, I think for
>> most humans it would be experienced as a confusing set of arcane and
>> arbitrary rules about what "=" means in Python.
>
> I respectfully disagree.  There are no "arcane and confusing rules"
> about "=", it's rather simple:
>
> "=" is always an assignment.
> "==" is always an equality check.

That's not the distinction I meant, I meant the difficulty of
explaining the discrepancies in this list:

a = 1 # Assignment
(a = 1) # Also assignment

a, b = 1, 2 # Tuple assignment
(a, b = 1, 2) # SyntaxError. Why?

a.b = 1 # Attribute assignment
(a.b = 1) # SyntaxError. Why?

a[b] = 1 # Subscript assignment
(a[b] = 1) # SyntaxError. Why?


(a=1), (b=2) # Two assignments
a=1, b=2 # SyntaxError. Why?

f(a=1, b=2) # Function call with keyword args
(a=1, b=2) # SyntaxError. Why?

if (a=1): pass # Assignment
if a=1: pass # SyntaxError. Why?

Whereas if binding expressions use a different symbol, the question is
far less likely to arise, and if it does come up, then the answer is
the same as the one for def statements vs lambda expressions: because
one is a statement, and the other is an expression.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Antoine Pitrou
On Tue, 24 Apr 2018 23:46:34 +1000
Nick Coghlan  wrote:
> On 24 April 2018 at 23:38, Yury Selivanov  wrote:
> > I propose to use the following syntax for assignment expressions:
> >
> > ( NAME = expr )
> >
> > I know that it was proposed before and this idea was rejected, because
> > accidentally using '=' in place of '==' is a pain point in
> > C/C++/JavaScript.
> >
> > That said, I believe we can still use this syntax as long as we impose
> > the following three restrictions on it:
> >
> > 1. Only NAME token is allowed as a single target.
> >
> > 2. Parenthesis are required.
> >
> > 3. Most importantly: it is *not* allowed to mask names in the current
> > local scope.  
> 
> While I agree this would be unambiguous to a computer, I think for
> most humans it would be experienced as a confusing set of arcane and
> arbitrary rules about what "=" means in Python.

If the ambition is to find a piece of syntax that reads as "binds",
then we can use a variation on the FLUFL operator: "<->".

Regards

Antoine.


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
On Tue, Apr 24, 2018 at 9:46 AM, Nick Coghlan  wrote:
> On 24 April 2018 at 23:38, Yury Selivanov  wrote:
>> I propose to use the following syntax for assignment expressions:
>>
>> ( NAME = expr )
>>
>> I know that it was proposed before and this idea was rejected, because
>> accidentally using '=' in place of '==' is a pain point in
>> C/C++/JavaScript.
>>
>> That said, I believe we can still use this syntax as long as we impose
>> the following three restrictions on it:
>>
>> 1. Only NAME token is allowed as a single target.
>>
>> 2. Parenthesis are required.
>>
>> 3. Most importantly: it is *not* allowed to mask names in the current
>> local scope.
>
> While I agree this would be unambiguous to a computer, I think for
> most humans it would be experienced as a confusing set of arcane and
> arbitrary rules about what "=" means in Python.

I respectfully disagree.  There are no "arcane and confusing rules"
about "=", it's rather simple:

"=" is always an assignment.
"==" is always an equality check.

Having two assignment operators feels way more arcane to me.
Especially in Python guided by "there should be one way" Zen.

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] assignment expressions: an alternative proposal

2018-04-24 Thread Nick Coghlan
On 24 April 2018 at 23:38, Yury Selivanov  wrote:
> I propose to use the following syntax for assignment expressions:
>
> ( NAME = expr )
>
> I know that it was proposed before and this idea was rejected, because
> accidentally using '=' in place of '==' is a pain point in
> C/C++/JavaScript.
>
> That said, I believe we can still use this syntax as long as we impose
> the following three restrictions on it:
>
> 1. Only NAME token is allowed as a single target.
>
> 2. Parenthesis are required.
>
> 3. Most importantly: it is *not* allowed to mask names in the current
> local scope.

While I agree this would be unambiguous to a computer, I think for
most humans it would be experienced as a confusing set of arcane and
arbitrary rules about what "=" means in Python.

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


[Python-Dev] assignment expressions: an alternative proposal

2018-04-24 Thread Yury Selivanov
I propose to use the following syntax for assignment expressions:

( NAME = expr )

I know that it was proposed before and this idea was rejected, because
accidentally using '=' in place of '==' is a pain point in
C/C++/JavaScript.

That said, I believe we can still use this syntax as long as we impose
the following three restrictions on it:

1. Only NAME token is allowed as a single target.

2. Parenthesis are required.

3. Most importantly: it is *not* allowed to mask names in the current
local scope.


Let's see how each restriction affects the syntax in detail:

(1) NAME tokens only:

  if (a[1] = value)# SyntaxError
  if (a.attr = value)  # SyntaxError

(2) Required parens disambiguate the new syntax from keyword-arguments
and prevent using '=' in place of '==':

   if a = value# SyntaxError
   if expr and a = value# SyntaxError

(3) No masking of existing names in local scope makes using '=' in
place of '==' by mistake even less probable:

   flag = get_flag()
   ...
   if (flag = 'win')# SyntaxError

   # or

   def foo(value):
  if (value = 1)   # SyntaxError

   # or

   py> (c = 1) and (c = 2)   # SyntaxError

   # etc


The following code snippets are perfectly valid though:

py> a = (b = (c = 3))
py> a, b, c
(3, 3, 3)

  # and

py> f = lambda x: x * 10
py> [[(y = f(x)), x/y] for x in range(1,5)]
[[10, 0.1], [20, 0.1], [30, 0.1], [40, 0.1]]

  # and

  def read():
  while (command = input("> ")) != "quit":
 print('you entered', command)

  # and

py> if (match = re.search(r'wor\w+', 'hello world')):
py. print(match)


  # and

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


Enabling '=' for assignment expressions introduces a limited form of
the more general assignment statement. It is designed to be useful in
expressions and is deliberately simple to make it hard for users to
shoot in the foot. The required Python grammar changes are simple and
unambiguous.

Although it is still possible to accidentally mask a global name or a
name from an outer scope, the risk of that is significantly lower than
masking a local name.  IDEs and linters can improve the usability
further by highlighting invalid or suspicious assignment expressions.

I believe that this syntax is the best of both worlds: it allows to
write succinct code just like PEP 572, but without introducing a new
':=' operator.

An implementation of this proposal is available here:
https://github.com/1st1/cpython/tree/assign.

If this idea is deemed viable I will write a PEP detailing the
grammar/compiler changes and syntax restrictions.

Thanks,
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-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 573 -- Module State Access from C Extension Methods

2018-04-24 Thread Nick Coghlan
On 24 April 2018 at 18:17, Jeroen Demeyer  wrote:
> In PEP 573, instead of passing the defining class to the C function, why not
> pass the function object itself? That is far more general: once you have the
> function object, you can still access the defining class using your
> PyCMethod_CLASS. It's also more future-proof: if we ever decide to add even
> more attributes to the function object, those could be accessed the same
> way.
>
> In PEP 575, I'm already proposing a flag (METH_ARG0_FUNCTION) to pass the
> function *instead* of self. Unless PEP 573 is rejected, maybe that should
> change to passing the function *in addition* to self.

That would definitely be an elegant way of addressing both use cases.

> Of course, this doesn't quite work with your current version of PEP 573
> since METH_METHOD really does two things: it changes the class of the
> function object (which is not a good idea anyway) and it changes the calling
> convention. It could work if you add mm_class to PyCFunctionObject instead
> of creating a new class.

Creating a new type in the module state access aimed to reduce the
potential for unintended side effects, but assuming we go ahead with
PEP 575's restructuring of the native function class heirarchy, I
agree it would make more sense to add it as a new capability within
that heirarchy, rather than adding a dedicated type for it.

Regarding the module state access PEP overall - I'm +1 on the proposed
changes (the PEP's been through a number of earlier rounds of
discussion on import-sig, and my feedback from those has already been
incorporated into the current version).

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 573 -- Module State Access from C Extension Methods

2018-04-24 Thread Jeroen Demeyer
In PEP 573, instead of passing the defining class to the C function, why 
not pass the function object itself? That is far more general: once you 
have the function object, you can still access the defining class using 
your PyCMethod_CLASS. It's also more future-proof: if we ever decide to 
add even more attributes to the function object, those could be accessed 
the same way.


In PEP 575, I'm already proposing a flag (METH_ARG0_FUNCTION) to pass 
the function *instead* of self. Unless PEP 573 is rejected, maybe that 
should change to passing the function *in addition* to self.


Of course, this doesn't quite work with your current version of PEP 573 
since METH_METHOD really does two things: it changes the class of the 
function object (which is not a good idea anyway) and it changes the 
calling convention. It could work if you add mm_class to 
PyCFunctionObject instead of creating a new class.



Jeroen.
___
Python-Dev mailing list
Python-Dev@python.org
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 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 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


  1   2   >