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

2018-04-25 Thread Stephen J. Turnbull
Chris Angelico writes:

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

Period here preferred.

 > and is easier to dictate to a student or junior programmer.

True but gratuitous.  It's also true that it's easier to dictate to
Guido or Tim, though you might be happier if you let them refactor!

___
Python-Dev mailing list
Python-Dev@python.org
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-25 Thread Stephen J. Turnbull
Devin Jeanpierre writes:

 > Some other programming languages (thinking of Racket) solve this by
 > having the debugger let you step through expression evaluation,
 > without editing the code.

Good tools are a wonderful thing, and I think pdb should be enhanced
that way (by somebody who has the time and interest, not me and not
necessarily you ;-).

Nevertheless, "printf debugging" continues to be very popular, and
good support for printf debugging is indeed the killer app for binding
expressions as far as I'm concerned.  Tim's humorous insight took me
from -0.8 all the way to

+1

Nice job, Chris!  Good luck with the pronouncement!

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Raymond Hettinger

> On Apr 26, 2018, at 12:40 AM, Tim Peters  wrote:
> 
> [Raymond Hettinger ]
>> After re-reading all the proposed code samples, I believe that
>> adopting the PEP will make the language harder to teach to people
>> who are not already software engineers.
> 
> Can you elaborate on that?  

Just distinguishing between =, :=, and == will be a forever recurring
discussion, far more of a source of confusion than the occasional
question of why Python doesn't have embedded assignment.

Also, it is of concern that a number of prominent core dev
respondents to this thread have reported difficulty scanning
the posted code samples.

> I've used dozens of languages over the
> decades, most of which did have some form of embedded assignment.

Python is special, in part, because it is not one of those languages.
It has virtues that make it suitable even for elementary school children.
We can show well-written Python code to non-computer folks and walk
them through what it does without their brains melting (something I can't
do with many of the other languages I've used).  There is a virtue
in encouraging simple statements that read like English sentences
organized into English-like paragraphs, presenting itself like
"executable pseudocode".

Perl does it or C++ does it is unpersuasive.  Its omission from Python
was always something that I thought Guido had left-out on purpose,
intentionally stepping away from constructs that would be of help
in an obfuscated Python contest.


> Yes, I'm a software engineer, but I've always pitched in on "help
> forums" too.

That's not really the same.  I've taught Python to many thousands
of professionals, almost every week for over six years.  That's given
me a keen sense of what is hard to teach.  It's okay to not agree
with my assessment, but I would like for fruits of my experience
to not be dismissed in a single wisp of a sentence.  Any one feature
in isolation is usually easy to explain, but showing how to combine
them into readable, expressive code is another matter.  And as
Yuri aptly noted, we spend more time reading code than writing code.
If some fraction of our users finds the code harder to scan
because the new syntax, then it would be a net loss for the language.

I hesitated to join this thread because you and Guido seemed to be
pushing back so hard against anyone's who design instincts didn't favor
the new syntax.  It would be nice to find some common ground and
perhaps stipulate that the grammar would grow in complexity, that a new
operator would add to the current zoo of operators, that the visual texture
of the language would change (and in a way that some including me
do not find pleasing), and that while simplest cases may afford
a small net win, it is a certitude that the syntax will routinely be
pushed beyond our comfort zone.

While the regex conditional example looks like a win, it is very modest win
and IMHO not worth the overall net increase language complexity.

Like Yuri, I'll drop-out now.  Hopefully, you all wind find some value
in what I had to contribute to the conversation.


Raymond







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


Re: [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Chris Angelico
On Thu, Apr 26, 2018 at 3:34 PM, Steven D'Aprano  wrote:
> On Thu, Apr 26, 2018 at 05:22:58PM +1200, Greg Ewing wrote:
>> Łukasz Langa wrote:
>> >What was its own assignment before
>> >now is part of the logic test. This saves on vertical whitespace but makes
>> >parsing and understanding logic tests harder.
>>
>> Another way to say this is that expressions are no longer
>> restricted to being trees, but can be general DAGs, which
>> require more mental effort to understand.
>
> Is that right? I presume you mean that there can be cycles in
> expressions involving binding-expressions. If not, what do you mean?
>
> Can you give an example of a Python expression, involving PEP 572
> binding-expressions, that is not a tree but a more general DAG or that
> contains cycles?

A DAG is a directed *acyclic* graph, so it still can't contain cycles.
But I have no idea what kind of expression isn't a tree as a
consequence of having an assignment in it.

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Steven D'Aprano
On Thu, Apr 26, 2018 at 05:22:58PM +1200, Greg Ewing wrote:
> Łukasz Langa wrote:
> >What was its own assignment before
> >now is part of the logic test. This saves on vertical whitespace but makes
> >parsing and understanding logic tests harder.
> 
> Another way to say this is that expressions are no longer
> restricted to being trees, but can be general DAGs, which
> require more mental effort to understand.

Is that right? I presume you mean that there can be cycles in 
expressions involving binding-expressions. If not, what do you mean?

Can you give an example of a Python expression, involving PEP 572 
binding-expressions, that is not a tree but a more general DAG or that 
contains cycles?



-- 
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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Greg Ewing

Łukasz Langa wrote:

What was its own assignment before
now is part of the logic test. This saves on vertical whitespace but makes
parsing and understanding logic tests harder.


Another way to say this is that expressions are no longer
restricted to being trees, but can be general DAGs, which
require more mental effort to understand.

Hmmm, maybe they should be called "spaghetti expressions". :-)

--
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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Łukasz Langa
[Uncle T]
> One language feature conspicuous by absence in newbie
> confusions was, consistently, assignment expressions.  Read any book
> or tutorial for such a language, and you'll find very little space
> devoted to them too.

Well, you have an entire code style built around this feature called Yoda 
conditions. You teach people on Day 1 to never ever confuse == with =. Some 
compilers even warn about this because so many people did it wrong.


> What's to learn?  If they understand "binding a name" _at all_ (which
> they must to even begin to write a non-trivial program), the only
> twist is that a binding expression returns the value being bound.

Ha, not in Python! Here we have *different syntax* for assignments in 
expressions. Well, you can also use it as a statement. But don't! We have a 
better one for that. And that one supports type annotations, can unpack and 
assign to many targets at the same time, and can even increment, multiply and 
so on, at once. But the other one can't.

So only use the Pascal one in expressions. But don't forget parentheses, 
otherwise it will bind the thing you probably didn't want anyway.

>> To my eyes, the examples give ample opportunity for being
>> misunderstood and will create a need to puzzle-out the intended semantics.
> 
> Some do, many don't.

As soon as we have to wrap a part of an expression in parentheses, parsing the 
entire thing becomes more complex. Often enough it will cause the expression to 
exceed whatever line length limit the codebase pledged not to exceed, causing 
one line to become three. And again, making it trickier for a regular Łukasz to 
understand what's going on.

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


Re: [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Tim Peters
[Raymond Hettinger ]
> After re-reading all the proposed code samples, I believe that
> adopting the PEP will make the language harder to teach to people
> who are not already software engineers.

Can you elaborate on that?  I've used dozens of languages over the
decades, most of which did have some form of embedded assignment.
Yes, I'm a software engineer, but I've always pitched in on "help
forums" too.  One language feature conspicuous by absence in newbie
confusions was, consistently, assignment expressions.  Read any book
or tutorial for such a language, and you'll find very little space
devoted to them too.

What's to learn?  If they understand "binding a name" _at all_ (which
they must to even begin to write a non-trivial program), the only
twist is that a binding expression returns the value being bound.
Binding expressions certainly wouldn't be the _first_ thing to teach
people.  But by the time it would make sense to teach them, it's hard
for me to grasp how a student could struggle with such a tiny
variation on what they've already learned (all the subtleties are in
what - exactly - "binding"means - which they already faced the first
time they saw "j = 1").


> To my eyes, the examples give ample opportunity for being
> misunderstood and will create a need to puzzle-out the intended semantics.

Some do, many don't.  The same can be said of a great many constructs ;-)

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


Re: [Python-Dev] Is PEP 572 really the most effective way to solve the problems it's targeting?

2018-04-25 Thread Ryan Gonzalez

On April 25, 2018 11:05:04 PM Steven D'Aprano  wrote:

On Wed, Apr 25, 2018 at 09:36:31PM -0500, Ryan Gonzalez wrote:


I have to say I'm not overly thrilled with PEP 572...it's almost odd,
because if you asked me back when I first joined this list when I was 13, I
would've no doubt said *YES*.

I have the opposite experience: I've warmed to it the more I have read
it. Before Chris had even written this PEP, there was a Python-Ideas
thread asking for dedicated syntax in comprehensions alone that would
have been equivalent to a binding-expression. I was rather negative
about the whole thing (but no where near as negative as I've been in
the past when this has come up before), until Chris pointed out that
such binding-expressions have value outside of comprehensions.


[...]
Now, what's the common theme here? **Declarations should be separate from
expressions.**

Declarations and assignments are not the same thing.

Yeah, this is what happens when I write these things when tired... I meant 
to also mention assignments here, and anywhere else I may have used 
"declaration".




We've got languages that range from baggage-filled to
functional to a bit of all of the above, and none of them have added
assignment *inside* an expression.

And your claim about assignment inside expressions is only true if you
ignore the languages where assignment is an expression with a return
value. You know, strange and exotic languages with hardly any users or
influence, like C, C++, C#, Java, Javascript, Ruby, Perl, PHP, Lisp ...

In the majority of these, however, mixing assignments into expressions is 
considered bad practice.


For instance:

- C++ core guidelines: 
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-complicated
- MediaWiki style guide: 
https://m.mediawiki.org/wiki/Manual:Coding_conventions/PHP


Some of the other languages (e.g. Perl) aren't some I'd regard as positive 
influences...




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


--
Ryan (ライアン)
Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else
https://refi64.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] Is PEP 572 really the most effective way to solve the problems it's targeting?

2018-04-25 Thread Tim Peters
[Ryan Gonzalez ]
> I have to say I'm not overly thrilled with PEP 572...it's almost odd,
> because if you asked me back when I first joined this list when I was 13, I
> would've no doubt said *YES*. But, since then, I've gone across many
> projects and languages, and fundamentally *I have never felt hurt by the
> lack of assignment in an expression*, and I always regretted every time I
> tried it in C or Crystal. I understand this experience is pretty
> insignificant in comparison to many of the wizards here, but I thought I'd
> still share it as an opener for what I'm about to say.

The older you get, the more you'll regret not still being 13 ;-)


> With this being said, I'd encourage everyone to take a bit of a step back:
> what exactly are people looking for in PEP 572?
>
> I see two main goals:
>
> - Assignment in a conditional structure.
> - Assignment in a list comprehension.
>
> Most other use cases would significantly hurt readability and seem pretty
> rare.

I haven't been much impressed by suggested uses outside conditional
contexts either.


> Now let's break down the top one:
>
> - Assignment in an if condition.
> - Assignment in a while condition.
>
> So there are roughly three main goals here overall. Now, are there better
> ways to solve these?
> ...
> C++ has recently solved the if condition by allowing declarations inside the
> conditions:

But C++ has always had assignment expressions.  This:

> if (auto a = 123; a != 456) {

is solving a different (albeit related) problem:  that C/C++ require
declaring variables before use.  Python doesn't.  They could have done
the same via, .e.g,,

{
auto a = 123;
if (a != 456) {
 ...
}
}

and still have had the scope of `a` limited to one block.
auto-initializers in conditionals just gave a bit of syntactic sugar
for what was already easily (although with more typing) done.


> Many languages have a 'let' expression (using Felix as my example):
>
> if let a = 1, b = 2 in a == b then

I don't read Felix, but I assume the _scope_ of `a` & `b` there ends
immediately before the "then".  If the names can't be used in the
_body_ of a Python `if` (or `while`) block, it's essentially useless
to allow binding names for use solely in the conditional test.

So it would help if you picked "real Python examples" from the many
other earlier messages in these threads.  Python expressions can't
span Python statement boundaries - only Python blocks can do that.  A
form of `let` that _would_ work would be block-structured:

let m = regexp.match(pattern. line) in:
if m:
print(m.group(0))

That solves "a scope problem" the current version of the PEP gave up
on, but in all other respects seems a step back from the current:

m = regexp.match(pattern, line)
if m:
print(m.group(0))


> Swift has taken a bit of a hybrid between the above two:
>
> if let a = 1, b = 2, a == b {

That seems plain incoherent ;-)


> Now, what's the common theme here? **Declarations should be separate from
> expressions.** We've got languages that range from baggage-filled to
> functional to a bit of all of the above, and none of them have added
> assignment *inside* an expression.

C++ and C have always had assignment expressions .  Ditto Java,
Javascript, Perl, Icon,  ... (many, many others).  I don't see a good
reason to grant that Felix and Swift are necessarily improvements over
the former (with the exception of Icon, which I'm merely fond of) very
widely used languages.


> The argument is roughly the same across all boards: you're putting major but
> easy-to-miss side effects in the midst of expressions that *seem* pure.
>
> All this is to say: I'd really encourage everyone here to think a bit more
> about *why* exactly you want this feature, and then think if there's really
> no better way. Any solution that separates declarations would be far more
> readable, (arguably) more Pythonic, and play more nicely with the new-ish
> typing features to boot

People have been trying for years.  If you come up with a realistic
(for Python) idea, that's great - share it!  But it's probably better
suited to python-ideas than python-dev.

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


Re: [Python-Dev] Is PEP 572 really the most effective way to solve the problems it's targeting?

2018-04-25 Thread Steven D'Aprano
On Wed, Apr 25, 2018 at 09:36:31PM -0500, Ryan Gonzalez wrote:
> 
> 
> I have to say I'm not overly thrilled with PEP 572...it's almost odd, 
> because if you asked me back when I first joined this list when I was 13, I 
> would've no doubt said *YES*.

I have the opposite experience: I've warmed to it the more I have read 
it. Before Chris had even written this PEP, there was a Python-Ideas 
thread asking for dedicated syntax in comprehensions alone that would 
have been equivalent to a binding-expression. I was rather negative 
about the whole thing (but no where near as negative as I've been in 
the past when this has come up before), until Chris pointed out that 
such binding-expressions have value outside of comprehensions.


[...]
> Now, what's the common theme here? **Declarations should be separate from 
> expressions.**

Declarations and assignments are not the same thing.


> We've got languages that range from baggage-filled to 
> functional to a bit of all of the above, and none of them have added 
> assignment *inside* an expression.

And your claim about assignment inside expressions is only true if you 
ignore the languages where assignment is an expression with a return 
value. You know, strange and exotic languages with hardly any users or 
influence, like C, C++, C#, Java, Javascript, Ruby, Perl, PHP, Lisp ... 


-- 
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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Raymond Hettinger


> On Apr 25, 2018, at 8:11 PM, Yury Selivanov  wrote:
> 
> FWIW I started my thread for allowing '=' in expressions to make sure that
> we fully explore that path.  I don't like ':=' and I thought that using '='
> can make the idea more appealing to myself and others. It didn't, sorry if
> it caused any distraction. Although adding a new ':=' operator isn't my main
> concern.
> 
> I think it's a fact that PEP 572 makes Python more complex.
> Teaching/learning Python will inevitably become harder, simply because
> there's one more concept to learn.
> 
> Just yesterday this snippet was used on python-dev to show how great the
> new syntax is:
> 
>  my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
> 
> To my eye this is an anti-pattern.  One line of code was saved, but the
> other line becomes less readable.  The fact that 'buf' can be used after
> that line means that it will be harder for a reader to trace the origin of
> the variable, as a top-level "buf = " statement would be more visible.
> 
> The PEP lists this example as an improvement:
> 
>  [(x, y, x/y) for x in input_data if (y := f(x)) > 0]
> 
> I'm an experienced Python developer and I can't read/understand this
> expression after one read. I have to read it 2-3 times before I trace where
> 'y' is set and how it's used.  Yes, an expanded form would be ~4 lines
> long, but it would be simple to read and therefore review, maintain, and
> update.
> 
> Assignment expressions seem to optimize the *writing code* part, while
> making *reading* part of the job harder for some of us.  I write a lot of
> Python, but I read more code than I write. If the PEP gets accepted I'll
> use
> the new syntax sparingly, sure.  My main concern, though, is that this PEP
> will likely make my job as a code maintainer harder in the end, not easier.
> 
> I hope I explained my -1 on the PEP without sounding emotional.

FWIW, I concur with all of Yuri's thoughtful comments.

After re-reading all the proposed code samples, I believe that
adopting the PEP will make the language harder to teach to people
who are not already software engineers.  To my eyes, the examples
give ample opportunity for being misunderstood and will create a
need to puzzle-out the intended semantics.

On the plus side, the proposal does address the occasional minor
irritant of writing an assignment on a separate line.  On the minus side,
the visual texture of the new code is less appealing. The proposal
also messes with my mental model for the distinction between
expressions and statements.

It probably doesn't matter at this point (minds already seem to be made up),
but put me down for -1.   This is a proposal we can all easily live without.


Raymond







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


Re: [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Wes Turner
On Wednesday, April 25, 2018, Łukasz Langa  wrote:

>
> On 25 Apr, 2018, at 5:20 PM, Chris Angelico  wrote:
>
> On Thu, Apr 26, 2018 at 10:11 AM, Yury Selivanov
>  wrote:
>
> Just yesterday this snippet was used on python-dev to show how great the
> new syntax is:
>
>  my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
>
> To my eye this is an anti-pattern.  One line of code was saved, but the
> other line becomes less readable.  The fact that 'buf' can be used after
> that line means that it will be harder for a reader to trace the origin of
> the variable, as a top-level "buf = " statement would be more visible.
>
>
> Making 'buf' more visible is ONLY a virtue if it's going to be used
> elsewhere. Otherwise, the name 'buf' is an implementation detail of
> the fact that this function wants both a buffer and a size.
>
>
> You're claiming that `:=` is nicer in this situation because it's less
> prominent than regular assignment and thus doesn't suggest that the name
> stays visible later.
>
> But as others said, `:=` *does* make the name visible later until the
> enclosing scope ends.  In fact, a large part of its appeal is that you
> can use the result later (as in the `re.search()` example).  Will it be
> visible enough to the reaser in those cases then?
>
> There seems to be a conflict there.
>
> The question of assignment visibility also makes me think about
> unintentional name shadowing::
>
> buf = some_value
>
> ...  # 20 lines
>
> my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
>
> ...  # 20 lines
>
> buf  # <-- What value does this have?
>
>
> Even if we're not using the call pattern, there can be plenty of logic
> tests which aren't very obvious::
>
> buf = some_value
>
> ...  # 20 lines
>
> if node.parent is not None and (buf := node.parent.buffer):
> ... # 10 lines
>
> ...  # 20 lines
>
> buf  # <-- What value does this have?
>
>
> This is even more interesting because now `buf` isn't rebound
> *always*.
>
> So if I'm confused about an unexpected change in value of `buf`, I'll
> skim the code, fail to find the assignment, and then grep for `buf =`
> and also fail to find the assignment.  Yes, I could have searched for
> just `buf` instead but that will give me too many false positives,
> especially if I'm using a primitive text editor search or don't know
> about \b in regular expressions.
>
> Debugging this can be confusing.  I know it can since a similar
> annoyance can be observed with the magic pseudo-scope of `except`::
>
> err = some_value
> try:
> ...
> except Error as err:
> ...
>
> err  # <-- now sometimes it's not defined
>
>
> Just like Barry, I debugged a few cases of this in the past and within
> larger functions this can be hard to find.
>

Would this make it easier to put too much code on one line?

Is there a good way to get *branch coverage* stats instead of just *line
coverage*?

Someone can probably explain with some tested pretty code for me why this
would be necessary or helpful; why it wouldn't make line coverage stats
more misleading for the sake of lazy?


>
> -- Ł
>
>
___
Python-Dev mailing list
Python-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] Is PEP 572 really the most effective way to solve the problems it's targeting?

2018-04-25 Thread Ryan Gonzalez



I have to say I'm not overly thrilled with PEP 572...it's almost odd, 
because if you asked me back when I first joined this list when I was 13, I 
would've no doubt said *YES*. But, since then, I've gone across many 
projects and languages, and fundamentally *I have never felt hurt by the 
lack of assignment in an expression*, and I always regretted every time I 
tried it in C or Crystal. I understand this experience is pretty 
insignificant in comparison to many of the wizards here, but I thought I'd 
still share it as an opener for what I'm about to say.




With this being said, I'd encourage everyone to take a bit of a step back: 
what exactly are people looking for in PEP 572?


I see two main goals:

- Assignment in a conditional structure.
- Assignment in a list comprehension.

Most other use cases would significantly hurt readability and seem pretty rare.

Now let's break down the top one:

- Assignment in an if condition.
- Assignment in a while condition.

So there are roughly three main goals here overall. Now, are there better 
ways to solve these?


(FWIW C solved the while condition one with the C-style for loop, but I'm 
pretty sure few people here would really go for that.)


C++ has recently solved the if condition by allowing declarations inside 
the conditions:


if (auto a = 123; a != 456) {

Many languages have a 'let' expression (using Felix as my example):

if let a = 1, b = 2 in a == b then

Swift has taken a bit of a hybrid between the above two:

if let a = 1, b = 2, a == b {

Now, what's the common theme here? **Declarations should be separate from 
expressions.** We've got languages that range from baggage-filled to 
functional to a bit of all of the above, and none of them have added 
assignment *inside* an expression.


The argument is roughly the same across all boards: you're putting major 
but easy-to-miss side effects in the midst of expressions that *seem* pure.


All this is to say: I'd really encourage everyone here to think a bit more 
about *why* exactly you want this feature, and then think if there's really 
no better way. Any solution that separates declarations would be far more 
readable, (arguably) more Pythonic, and play more nicely with the new-ish 
typing features to boot


I understand reluctance to add a syntax exception like this, but I really 
feel it'd be worth it.


As a side note, I was a strong supporter of comprehension generalizations, 
f-strings, *and* dataclasses. However, this proposal seems a bit ugly and 
excessive for what it's trying to accomplish.


P.S. Yes, the unmatched curly braces were intentional to drive you crazy 
for a few hours. I blame Randall Monroe. You're welcome.


--
Ryan (ライアン)
Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else
https://refi64.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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Łukasz Langa

> On 25 Apr, 2018, at 5:20 PM, Chris Angelico  wrote:
> 
> On Thu, Apr 26, 2018 at 10:11 AM, Yury Selivanov
>  wrote:
>> Just yesterday this snippet was used on python-dev to show how great the
>> new syntax is:
>> 
>>  my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
>> 
>> To my eye this is an anti-pattern.  One line of code was saved, but the
>> other line becomes less readable.  The fact that 'buf' can be used after
>> that line means that it will be harder for a reader to trace the origin of
>> the variable, as a top-level "buf = " statement would be more visible.
> 
> Making 'buf' more visible is ONLY a virtue if it's going to be used
> elsewhere. Otherwise, the name 'buf' is an implementation detail of
> the fact that this function wants both a buffer and a size.

You're claiming that `:=` is nicer in this situation because it's less
prominent than regular assignment and thus doesn't suggest that the name
stays visible later.

But as others said, `:=` *does* make the name visible later until the
enclosing scope ends.  In fact, a large part of its appeal is that you
can use the result later (as in the `re.search()` example).  Will it be
visible enough to the reaser in those cases then?

There seems to be a conflict there.

The question of assignment visibility also makes me think about
unintentional name shadowing::

buf = some_value

...  # 20 lines

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

...  # 20 lines

buf  # <-- What value does this have?


Even if we're not using the call pattern, there can be plenty of logic
tests which aren't very obvious::

buf = some_value

...  # 20 lines

if node.parent is not None and (buf := node.parent.buffer):
... # 10 lines

...  # 20 lines

buf  # <-- What value does this have?


This is even more interesting because now `buf` isn't rebound
*always*.

So if I'm confused about an unexpected change in value of `buf`, I'll
skim the code, fail to find the assignment, and then grep for `buf =`
and also fail to find the assignment.  Yes, I could have searched for
just `buf` instead but that will give me too many false positives,
especially if I'm using a primitive text editor search or don't know
about \b in regular expressions.

Debugging this can be confusing.  I know it can since a similar
annoyance can be observed with the magic pseudo-scope of `except`::

err = some_value
try:
...
except Error as err:
...

err  # <-- now sometimes it's not defined


Just like Barry, I debugged a few cases of this in the past and within
larger functions this can be hard to find.

-- Ł



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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Yury Selivanov
On Wed, Apr 25, 2018 at 8:22 PM Chris Angelico  wrote:
[..]
> >   my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
> >
> > To my eye this is an anti-pattern.  One line of code was saved, but the
> > other line becomes less readable.  The fact that 'buf' can be used after
> > that line means that it will be harder for a reader to trace the origin
of
> > the variable, as a top-level "buf = " statement would be more visible.

> Making 'buf' more visible is ONLY a virtue if it's going to be used
> elsewhere. Otherwise, the name 'buf' is an implementation detail of
> the fact that this function wants both a buffer and a size. Should you
> want to expand this out over more lines, you could do this:

Chris, you didn't read that paragraph in my email to the end or I did a
poor job at writing it.

My point is that "buf" can still be used below that line, and therefore
sometimes it will be used, as a result of quick refactoring or poor coding
style.  It's just how things happen when you write code: it gets rewritten
and parts of it left outdated or not properly revised.  *If* "buf" is used
below that line it *will* be harder to find where it was initially set.

Anyways, I don't want to distract everyone further so I'm not interested
in continuing the discussion about what is readable and what is not.
My own opinion on this topic is unlikely to change.  I wanted to explain
my -1; hopefully it will be noted.

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Antoine Pitrou
On Thu, 26 Apr 2018 10:20:40 +1000
Chris Angelico  wrote:
> On Thu, Apr 26, 2018 at 10:11 AM, Yury Selivanov
>  wrote:
> > Just yesterday this snippet was used on python-dev to show how great the
> > new syntax is:
> >
> >   my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
> >
> > To my eye this is an anti-pattern.  One line of code was saved, but the
> > other line becomes less readable.  The fact that 'buf' can be used after
> > that line means that it will be harder for a reader to trace the origin of
> > the variable, as a top-level "buf = " statement would be more visible.  
> 
> Making 'buf' more visible is ONLY a virtue if it's going to be used
> elsewhere. Otherwise, the name 'buf' is an implementation detail of
> the fact that this function wants both a buffer and a size. Should you
> want to expand this out over more lines, you could do this:
> 
> template = [None]
> buf = template*get_size()
> length = len(buf)
> my_func(arg, buffer=buf, size=length)
> 
> What are the names 'template' and 'length' achieving? Why should they
> claim your attention?

What is the name 'buf' in the binding expression achieving? Why should
it claim my attention?
It's not any different: it's just something that's used in a statement
then unnecessary.  Yet it will persist until the end of the enclosing
scope, being retained for no reason.  Perhaps we need C-like nested
scopes, if such is the concern about names that live for too long?

(of course, the fact that `my_func` needs you to pass its argument's
length as a separate argument, while it could compute it by itself, is
a bit silly)

As a side note, personally, I'm usually much more concerned about the
lifetime of *values* than the lifetime of names.  The latter are cheap,
the former can represent expensive resources.

Regards

Antoine.



> They are useless relics of a done-and-dusted
> calculation, being retained for no reason. They do not deserve
> top-level placement.
> 
> The form as given above is starting to get a bit noisy, but I strongly
> disagree that 'buf' deserves to be a stand-alone name. It is as
> valueless as 'template' is.
> 
> 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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Chris Angelico
On Thu, Apr 26, 2018 at 10:11 AM, Yury Selivanov
 wrote:
> Just yesterday this snippet was used on python-dev to show how great the
> new syntax is:
>
>   my_func(arg, buffer=(buf := [None]*get_size()), size=len(buf))
>
> To my eye this is an anti-pattern.  One line of code was saved, but the
> other line becomes less readable.  The fact that 'buf' can be used after
> that line means that it will be harder for a reader to trace the origin of
> the variable, as a top-level "buf = " statement would be more visible.

Making 'buf' more visible is ONLY a virtue if it's going to be used
elsewhere. Otherwise, the name 'buf' is an implementation detail of
the fact that this function wants both a buffer and a size. Should you
want to expand this out over more lines, you could do this:

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

What are the names 'template' and 'length' achieving? Why should they
claim your attention? They are useless relics of a done-and-dusted
calculation, being retained for no reason. They do not deserve
top-level placement.

The form as given above is starting to get a bit noisy, but I strongly
disagree that 'buf' deserves to be a stand-alone name. It is as
valueless as 'template' is.

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Antoine Pitrou
On Wed, 25 Apr 2018 18:55:56 -0500
Tim Peters  wrote:
> 
> > the shorthand version appears completely bonkers.  
> 
> I wouldn't go that far, but I already said I wouldn't write it that way.
> 
> However, without looking at real code, people are just flat-out
> guessing about how bad - or good - things _can_ get, no matter how
> confident they sound.
> 
> So at least give me credit for presenting the _worst_ brief
> binding-expression example you've seen too ;-)

I had no idea you were a bit short on them, so I'll gladly give you
credits for it :-)  But I hope you'll use them responsibly!

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Yury Selivanov
On Wed, Apr 25, 2018 at 5:58 PM Guido van Rossum  wrote:
[..]
> It was meant dismissive. With Chris, I am tired of every core dev
starting their own thread about how PEP 572 threatens readability or
doesn't reach the bar for new syntax (etc.). These arguments are entirely
emotional and subjective.

FWIW I started my thread for allowing '=' in expressions to make sure that
we fully explore that path.  I don't like ':=' and I thought that using '='
can make the idea more appealing to myself and others. It didn't, sorry if
it caused any distraction. Although adding a new ':=' operator isn't my main
concern.

I think it's a fact that PEP 572 makes Python more complex.
Teaching/learning Python will inevitably become harder, simply because
there's one more concept to learn.

Just yesterday this snippet was used on python-dev to show how great the
new syntax is:

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

To my eye this is an anti-pattern.  One line of code was saved, but the
other line becomes less readable.  The fact that 'buf' can be used after
that line means that it will be harder for a reader to trace the origin of
the variable, as a top-level "buf = " statement would be more visible.

The PEP lists this example as an improvement:

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

I'm an experienced Python developer and I can't read/understand this
expression after one read. I have to read it 2-3 times before I trace where
'y' is set and how it's used.  Yes, an expanded form would be ~4 lines
long, but it would be simple to read and therefore review, maintain, and
update.

Assignment expressions seem to optimize the *writing code* part, while
making *reading* part of the job harder for some of us.  I write a lot of
Python, but I read more code than I write. If the PEP gets accepted I'll
use
the new syntax sparingly, sure.  My main concern, though, is that this PEP
will likely make my job as a code maintainer harder in the end, not easier.

I hope I explained my -1 on the PEP without sounding emotional.

Thank you,
Yury




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] Visual similarity of "=" and "==" (in context of PEP 572)

2018-04-25 Thread Chris Angelico
On Thu, Apr 26, 2018 at 9:54 AM, Mikhail V  wrote:
> Since the discussion about operator choice has completely migrated
> here, I'll put my note also here.
> From the very beginning of PEP 572 discussion I have noticed
> a strange fact - there is told a lot about visual similarity
> of "=" and "==" in Python.
> *Same is told in the PEP 572 (frequently asked question)
>  as the reason for rejection of "=" as operator.*
>
> Hope you get my point here.
> IMO either the PEP 572 should remove or at
> least rephrase this point somehow or, even better,
> concentrate on something more convincing in this regard.

https://www.python.org/dev/peps/pep-0572/#why-not-just-turn-existing-assignment-into-an-expression

Half a century of C programming demonstrates that this is ample argument.

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


[Python-Dev] Visual similarity of "=" and "==" (in context of PEP 572)

2018-04-25 Thread Mikhail V
Since the discussion about operator choice has completely migrated
here, I'll put my note also here.
>From the very beginning of PEP 572 discussion I have noticed
a strange fact - there is told a lot about visual similarity
of "=" and "==" in Python.
*Same is told in the PEP 572 (frequently asked question)
 as the reason for rejection of "=" as operator.*

I realize that currently there are other technical arguments against "=",
but I am the opinion that this very reason,
namely similarity of "=" and "==",  cannot be taken
seriously.

I'll try to explain:
I have opened Notepad++ and  went to syntax highlighting
configurator. It took me 2 minutes to choose a syntax setup
that defines "==" (and other comparison operators if you wish)
as a token with custom style.
Now I can apply *custom color and size* to it and
this alone makes the operator very well seen and different from "=".

If that is not enough, I can set different *font* for the operator:
so I can basically turn "==" into anything I want.
With this in mind, I personally can't understand why you
complain about "=="?

Ok, you could say - not all editors can do this.
But even without that tweaks - I still don't find the
problem worth exaggeration.
It is not like I accidentally choose very similar names
for variables and then spend an hour trying to figure out
where is the bug comes from. With "==" it just takes some
attention to look at -if- statements and recheck if I
write "==" and not "=" where I need comparison.

I see it as as a "typo-magnet" but no way as a "bug-magnet" as it
was claimed repeatedly in the discussion.
A programmer already knows about this similarity and can
fix the typos easily.

The ":=" operator is of course slightly more different, but
still, only _slightly_ better in this regard.

With that said, I am not much interested in either
adding of the expression assignment, although I am
really worrying about the reasoning made about "="
and "==" in the discussion.

Hope you get my point here.
IMO either the PEP 572 should remove or at
least rephrase this point somehow or, even better,
concentrate on something more convincing in this regard.

Also I think Yury has made good point about the
introduction of ":=" -- it would co-exist with the "=".
So imo, if you get familiar with ":=", later on
it will just cause additional visual noise.
And I don't think a regular user will be much
interested in nuances of internal implementation
of new assignment - they'll just follow the logic
of the code and another operator will constantly
gain unnecessary attention at reading.


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


Re: [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Tim Peters
[Tim]
 To my eyes, this is genuinely harder to follow, despite its relative 
 brevity:

 while total != (total := total + term):

[Antoine]
>>> Does it even work?  Perhaps if the goal is to stop when total is NaN,
>>> but otherwise?

[Chris]
>> Yes, it does, because the first "total" is looked up before the
>> rebinding happens. It's 100% unambiguous to the compiler... but still
>> pretty unclear to a human. And I think the multiple use of 'total' is
>> to blame for that. So I agree with Tim that this particular example is
>> better in longhand.

[Antoine]
> "Better" is an understatement :-(  Now that I understood it (thanks
> for the explanation),

Ah, sorry - I had no idea it was the "left to right evaluation" part
you weren't seeing.  Next time explain why you think something is
broken?


> the shorthand version appears completely bonkers.

I wouldn't go that far, but I already said I wouldn't write it that way.

However, without looking at real code, people are just flat-out
guessing about how bad - or good - things _can_ get, no matter how
confident they sound.

So at least give me credit for presenting the _worst_ brief
binding-expression example you've seen too ;-)
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2018-04-25 Thread Chris Angelico
On Thu, Apr 26, 2018 at 9:05 AM, Victor Stinner  wrote:
>> # 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]
>
> What do you think of adding the variant without the new ":=" syntax?
> It would help to see the benefit of the new ":=" syntax, and help to
> compare the two syntaxes.
>
> if:
>   if (match := pattern.search(data)) is not None: ...
> vs
>   match = pattern.search(data)
>   if match is not None: ...
>
> while:
>   while (value := read_next_item()) is not None: ...
> vs
>   while True:
> value = read_next_item()
> if value is None: break
> ...
>
> list-comprehension:
>   filtered_data = [y for x in data if (y := f(x)) is not None]
> vs
>   filtered_data = [f(x) for x in data]
>   filtered_data = [x for x in filtered_data if x is not None]

Doing that for everything would put the PEP solidly into "TL;DR"
territory, I'm afraid. There's already too much verbiage in some of
those sections.

Plus, we'd get right back into debates about how if you just change
your intended semantics slightly, there's a completely different way
to achieve something actually quite different, and we've already been
around that a few times already.

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] The new and improved PEP 572, same great taste with 75% less complexity!

2018-04-25 Thread Victor Stinner
> # 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]

What do you think of adding the variant without the new ":=" syntax?
It would help to see the benefit of the new ":=" syntax, and help to
compare the two syntaxes.

if:
  if (match := pattern.search(data)) is not None: ...
vs
  match = pattern.search(data)
  if match is not None: ...

while:
  while (value := read_next_item()) is not None: ...
vs
  while True:
value = read_next_item()
if value is None: break
...

list-comprehension:
  filtered_data = [y for x in data if (y := f(x)) is not None]
vs
  filtered_data = [f(x) for x in data]
  filtered_data = [x for x in filtered_data if x is not None]

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


Re: [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Antoine Pitrou
On Thu, 26 Apr 2018 08:38:51 +1000
Chris Angelico  wrote:

> On Thu, Apr 26, 2018 at 8:08 AM, Antoine Pitrou  wrote:
> > On Wed, 25 Apr 2018 16:55:43 -0500
> > Tim Peters  wrote:  
> >>
> >> To my eyes, this is genuinely harder to follow, despite its relative 
> >> brevity:
> >>
> >> while total != (total := total + term):  
> >
> > Does it even work?  Perhaps if the goal is to stop when total is NaN,
> > but otherwise?  
> 
> Yes, it does, because the first "total" is looked up before the
> rebinding happens. It's 100% unambiguous to the compiler... but still
> pretty unclear to a human. And I think the multiple use of 'total' is
> to blame for that. So I agree with Tim that this particular example is
> better in longhand.

"Better" is an understatement :-(  Now that I understood it (thanks
for the explanation), the shorthand version appears completely bonkers.

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Guido van Rossum
On Wed, Apr 25, 2018 at 3:15 PM, Ethan Furman  wrote:

> On 04/25/2018 02:55 PM, Tim Peters wrote:
>
>> To my eyes, this is genuinely harder to follow, despite its relative
>> brevity:
>>
>>  while total != (total := total + term):
>>  term *= mx2 / (i*(i+1))
>>  i += 2
>>  return total
>>
>> So I wouldn't use binding expressions in that case.  I don't have a
>> compelling head argument for _why_ I find the latter spelling harder
>> to follow, but I don't need a theory to know that I in fact do.
>>
>
> I know why I do:  I see "while total != total" and my gears start
> stripping.  On the other hand,
>
>   while total != (total + term as total):
>  ...
>
> I find still intelligible.  (Yes, I know "as" is dead, just wanted to
> throw that out there.)
>

The problem with either variant is that they hinge on subtle left-to-right
evaluation rules. Python tries to promise left-to-right evaluation "except
when it doesn't apply", e.g. in assignments the RHS is typically evaluated
before subexpressions in the LHS: a[f()] = g() calls g() before f().

The example is supposed to load the left operand to != on the stack before
loading the right operand, but the rule that says the left operand is
evaluated before the right operand is much weaker than other evaluation
order rules (like the rule stating that the arguments are evaluated before
the function is called -- and before you laugh, in Algol-60 that wasn't
always the case).

This argument applies regardless of which syntactic form you use, and no
matter what we choose, the PEP will have to clarify evaluation order in
more cases than the current reference manual. (IIRC Nathaniel brought this
up.)

-- 
--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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Chris Angelico
On Thu, Apr 26, 2018 at 8:08 AM, Antoine Pitrou  wrote:
> On Wed, 25 Apr 2018 16:55:43 -0500
> Tim Peters  wrote:
>>
>> To my eyes, this is genuinely harder to follow, despite its relative brevity:
>>
>> while total != (total := total + term):
>
> Does it even work?  Perhaps if the goal is to stop when total is NaN,
> but otherwise?

Yes, it does, because the first "total" is looked up before the
rebinding happens. It's 100% unambiguous to the compiler... but still
pretty unclear to a human. And I think the multiple use of 'total' is
to blame for that. So I agree with Tim that this particular example is
better in longhand.

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Ethan Furman

On 04/25/2018 03:15 PM, Ethan Furman wrote:

On 04/25/2018 02:55 PM, Tim Peters wrote:


This becomes a question of seasoned judgment.  For example, here's a
real loop summing a series expansion, until the new terms become so
small they make no difference to the running total (a common enough
pattern in code slinging floats or decimals):

 while True:
 old = total
 total += term
 if old == total:
 return total
 term *= mx2 / (i*(i+1))
 i += 2

To my eyes, this is genuinely harder to follow, despite its relative brevity:

 while total != (total := total + term):
 term *= mx2 / (i*(i+1))
 i += 2
 return total

So I wouldn't use binding expressions in that case.  I don't have a
compelling head argument for _why_ I find the latter spelling harder
to follow, but I don't need a theory to know that I in fact do.


I know why I do:  I see "while total != total" and my gears start stripping.  
On the other hand,

   while total != (total + term as total):
  ...

I find still intelligible.  (Yes, I know "as" is dead, just wanted to throw 
that out there.)


Having said that, since whomever mentioned reading ":=" as "which is", I'm good with 
":=".

--
~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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Tim Peters
[Tim]
>> To my eyes, this is genuinely harder to follow, despite its relative brevity:
>>
>> while total != (total := total + term):

[Antoine]
> Does it even work?  Perhaps if the goal is to stop when total is NaN,
> but otherwise?

I don't follow you.  You snipped all the text explaining why it would
work, so trying reading that again?  When, e.g., `total` reaches 1.0
and `term` reaches 1e-30, this becomes:

while 1.0 != (total := 1.0 + 1-e30):

which leaves `total` unchanged (1.0 + 1e-30 == 1.0) and then

while 1.0 != 1.0:

causes the loop to exit (`while False:`).


>> For that reason, the messages that sway me are those showing real
>> code, or at least plausibly realistic code.  In the majority of those
>> so far, binding expressions would be a small-to-major win.

> I'm sure it's possible to find thousands of line of code where binding
> expressions wouldn't be a win, but I'm not sure that would be a
> constructive use of mailing-list bandwidth.

And that "argument" is? ;-)

Note that I managed to move the PEP _away_ from general "assignment
expressions" to the much simpler "binding expressions" precisely _by_
illustrating, via real code, why the generality of the former wasn't
actually useful in any case I looked at.  If something is always - or
almost always - useless, that can be shown via considering realistic
code.  That was far more productive than endless abstract debates.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Steven D'Aprano
On Wed, Apr 25, 2018 at 01:55:37PM -0700, Łukasz Langa wrote:
> 
> > On 25 Apr, 2018, at 1:28 PM, Guido van Rossum  wrote:
> > 
> > You don't seem to grasp the usability improvements this will give. I hear 
> > you but at this point appeals to Python's "Zen" don't help you.
> 
> This reads dismissive to me. I did read the PEP and followed the discussion on
> python-dev. I referred to PEP 20 because it distills what's unique about the
> value proposition of Python. It's our shared vocabulary.

Every programming language has a shared vocabulary. That's hardly unique 
to Python.


> Can you address the specific criticism I had? To paraphrase it without PEP 20
> jargon:
> 
> > (name := expression) makes code less uniform.  It inserts more information
> > into a place that is already heavily packed with information (logic tests).

I'm not Guido, but I'll make an attempt.

I think the comment about "less uniform" isn't meaningful. Uniform in 
what way?

I don't even know how to interpret the uniform comment here, unless you 
mean to imply that every statement and expression in Python currently 
has the same information density, and binding-expressions will violate 
that. That's clearly not the case, so I'm left puzzled by what you mean.

As for your observation that binding-expressions don't reduce 
complexity, they merely move it, I think you may be right. But 
then it is a truism that complexity is never reduced, only moved, so 
that's likely to be true for any feature (including existing ones). 
Should we move back to assembly language programming because Python 
hasn't reduced complexity, only moved it? I don't think so.

Clearly binding-expressions do add a little more complexity to the 
language, and they do move code from vertically separated statements to 
horizontally laid-out expressions.

But why is this necessarily a bad thing? Exactly the same complaint can 
be made about comprehensions, and look at how wildly successful they 
have been.

Offset against the increase in horizontal complexity is a corresponding 
decrease in vertical complexity, and that's beneficial.

Whatever cost they have has to be offset against the benefits, and I 
think the feature will come ahead on the plus side overall. Of course, 
like any syntactic feature, it may be abused by those who (by accident 
or design) write obfuscated or excessively complex code. We shouldn't 
ignore that risk, but nor should we use that as an excuse to dismiss the 
feature's benefits.


-- 
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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Ethan Furman

On 04/25/2018 02:55 PM, Tim Peters wrote:


This becomes a question of seasoned judgment.  For example, here's a
real loop summing a series expansion, until the new terms become so
small they make no difference to the running total (a common enough
pattern in code slinging floats or decimals):

 while True:
 old = total
 total += term
 if old == total:
 return total
 term *= mx2 / (i*(i+1))
 i += 2

To my eyes, this is genuinely harder to follow, despite its relative brevity:

 while total != (total := total + term):
 term *= mx2 / (i*(i+1))
 i += 2
 return total

So I wouldn't use binding expressions in that case.  I don't have a
compelling head argument for _why_ I find the latter spelling harder
to follow, but I don't need a theory to know that I in fact do.


I know why I do:  I see "while total != total" and my gears start stripping.  
On the other hand,

  while total != (total + term as total):
 ...

I find still intelligible.  (Yes, I know "as" is dead, just wanted to throw 
that out there.)

--
~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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Antoine Pitrou
On Wed, 25 Apr 2018 16:55:43 -0500
Tim Peters  wrote:
> 
> To my eyes, this is genuinely harder to follow, despite its relative brevity:
> 
> while total != (total := total + term):

Does it even work?  Perhaps if the goal is to stop when total is NaN,
but otherwise?

> For that reason, the messages that sway me are those showing real
> code, or at least plausibly realistic code.  In the majority of those
> so far, binding expressions would be a small-to-major win.

I'm sure it's possible to find thousands of line of code where binding
expressions wouldn't be a win, but I'm not sure that would be a
constructive use of mailing-list bandwidth.

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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Guido van Rossum
On Wed, Apr 25, 2018 at 1:55 PM, Łukasz Langa  wrote:

>
> > On 25 Apr, 2018, at 1:28 PM, Guido van Rossum  wrote:
> >
> > You don't seem to grasp the usability improvements this will give. I
> hear you but at this point appeals to Python's "Zen" don't help you.
>
> This reads dismissive to me. I did read the PEP and followed the
> discussion on
> python-dev.


It was meant dismissive. With Chris, I am tired of every core dev starting
their own thread about how PEP 572 threatens readability or doesn't reach
the bar for new syntax (etc.). These arguments are entirely emotional and
subjective.

And that's how big decisions get made. Nobody can predict the outcome with
sufficient accuracy. It's like buying a new car or house. In the end you
decide with your gut.


> I referred to PEP 20 because it distills what's unique about the
> value proposition of Python. It's our shared vocabulary.
>

It's poetry, not a set of axioms. You can't *prove* anything with an appeal
to PEP 20. You can appeal to it, for sure, but such an appeal *by
definition* is subjective and emotional. (There's Only One Way To Do It?
Give me a break. :-)


> Can you address the specific criticism I had? To paraphrase it without PEP
> 20
> jargon:
>
> > (name := expression) makes code less uniform.  It inserts more
> information
> > into a place that is already heavily packed with information (logic
> tests).
>

Most Python features make code less uniform in order to make it less
repetitive. (Who needs classes? :-)

-- 
--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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Tim Peters
[Guido]
>> You don't seem to grasp the usability improvements this will give.
>> I hear you but at this point appeals to Python's "Zen" don't help you.

[Łukasz Langa ]
> This reads dismissive to me. I did read the PEP and followed the discussion on
> python-dev. I referred to PEP 20 because it distills what's unique about the
> value proposition of Python. It's our shared vocabulary.
>
> Can you address the specific criticism I had? To paraphrase it without PEP 20
> jargon:

>  (name := expression) makes code less uniform.  It inserts more information
>   into a place that is already heavily packed with information (logic tests).

I'll take a crack at that.  It's not about "head arguments" at all.  I
sat out the first hundred messages about this on python-ideas, and
looked at code instead.  What I found had little to do with any of the
head (abstract) arguments passionately debated for the duration ;-)

In real life, I found a great many conditional tests that not only
weren't "heavily packed" with information, they were simply of the
form:

NAME = expression
if NAME:
... use NAME ...

That looks more like assembly language than Python ;-)  I saw no harm
at all, and a little gain, in

if NAME := expression:
... use NAME ...

instead.  But even a little gain adds up when it happens so often.

Of course there have been better examples given of bigger gains.  But
in no case have the tests in those examples been "heavily packed with
information".  If they had been, I would have suggested instead
breaking the test clauses _out_ of the conditional statements, and
giving them names each on their own dedicated lines, with comments
explaining what the heck the _intents_ are, even at the cost of adding
an indentation level or two. Sometimes conditionals are _already_ "too
dense".  But more often they're very sparse.

This becomes a question of seasoned judgment.  For example, here's a
real loop summing a series expansion, until the new terms become so
small they make no difference to the running total (a common enough
pattern in code slinging floats or decimals):

while True:
old = total
total += term
if old == total:
return total
term *= mx2 / (i*(i+1))
i += 2

To my eyes, this is genuinely harder to follow, despite its relative brevity:

while total != (total := total + term):
term *= mx2 / (i*(i+1))
i += 2
return total

So I wouldn't use binding expressions in that case.  I don't have a
compelling head argument for _why_ I find the latter spelling harder
to follow, but I don't need a theory to know that I in fact do.

But neither do I need a compelling head argument for "why" to know
that in many other cases I find that the use of binding expressions
improves the code.  You shouldn't believe me even if I pretended to
have one and passionately argued for it.  But, by the same token, I'm
spectacularly unmoved by other peoples' head arguments.

For that reason, the messages that sway me are those showing real
code, or at least plausibly realistic code.  In the majority of those
so far, binding expressions would be a small-to-major win.
___
Python-Dev mailing list
Python-Dev@python.org
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-25 Thread Devin Jeanpierre
On Wed, Apr 25, 2018 at 2:17 PM, Terry Reedy  wrote:
> On 4/25/2018 6:10 AM, Steve Holden wrote:
>> Indeed, in the cases where I currently find myself unwrapping expressions
>> to capture their values in local variables for debugging purposes it would
>> usually be far less intrusive to bind a name to the expression inline, then
>> use the debugger to inspect the value.
>
>
> I agree that this is a definite plus feature.  Being able to tag
> subexpressions would make visual debuggers that show all local variables as
> one steps (like IDLE's) even more useful relative to print statements.

Some other programming languages (thinking of Racket) solve this by
having the debugger let you step through expression evaluation,
without editing the code.

e.g. in the line x = 1 + 2 * 3, we might step through and first
evaluate 2*3 (-> 6), and then 1 +  (-> 7). Similar to how
Python already lets you step into and see the result of function
calls. This is especially powerful in visual debuggers, where the
stepping and output can be displayed very intuitively.

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


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

2018-04-25 Thread Terry Reedy

On 4/25/2018 6:10 AM, Steve Holden wrote:
On Wed, Apr 25, 2018 at 4:56 AM, Tim Peters > wrote:


[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 ;-)

​You just don't realise how perspicacious you truly are, Tim!
​

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


​Indeed, in the cases where I currently find myself unwrapping 
expressions to capture their values in local variables for debugging 
purposes it would usually be far less intrusive to bind a name to the 
expression inline, then use the debugger to inspect the value.


I agree that this is a definite plus feature.  Being able to tag 
subexpressions would make visual debuggers that show all local variables 
as one steps (like IDLE's) even more useful relative to print statements.


--
Terry Jan Reedy


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


Re: [Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Łukasz Langa

> On 25 Apr, 2018, at 1:24 PM, Chris Angelico  wrote:
> 
> On Thu, Apr 26, 2018 at 6:21 AM, Łukasz Langa  wrote:
>> := also goes against having one obvious way to do it. Since it's an 
>> expression,
>> it can also be placed on its own line or in otherwise weird places like
>> function call arguments. I anticipate PEP 8 would have to be extended to
>> explicitly discourage such abuse. Linters would grow rules against it. This 
>> is
>> noise.
> 
> Does this argument also apply to the if/else expression? Do linters
> need rules to advise against people writing code like:
> 
> print(x) if x is None else print(y)
> 
> ? It's perfectly legal to write code like this. But I don't see people
> abusing this sort of thing.

Ternary expressions are different because their flow is deliberately different
from a regular if statement.  It's also different from the C equivalent.
`:=` on the other hand is deciptively similar to `=`.

But yeah, I think worrying about abuse of the feature is a red herring.  The
gist of my criticism of your PEP is about the decreased balance in information
density.

-- Ł


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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Łukasz Langa

> On 25 Apr, 2018, at 1:28 PM, Guido van Rossum  wrote:
> 
> You don't seem to grasp the usability improvements this will give. I hear you 
> but at this point appeals to Python's "Zen" don't help you.

This reads dismissive to me. I did read the PEP and followed the discussion on
python-dev. I referred to PEP 20 because it distills what's unique about the
value proposition of Python. It's our shared vocabulary.

Can you address the specific criticism I had? To paraphrase it without PEP 20
jargon:

> (name := expression) makes code less uniform.  It inserts more information
> into a place that is already heavily packed with information (logic tests).

-- Ł



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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Guido van Rossum
A very emotional appeal, you don't seem to grasp the usability improvements
this will give. I hear you but at this point appeals to Python's "Zen"
don't help you.

On Wed, Apr 25, 2018 at 1:21 PM, Łukasz Langa  wrote:

> PEP 572 caused a strong emotional reaction in me. I wanted to first
> understand
> my intuitive objection to the idea before posting anything.
>
> I feel that (name := expression) doesn't fit the narrative of PEP 20. It
> doesn't remove complexity, it only moves it. What was its own assignment
> before
> now is part of the logic test. This saves on vertical whitespace but makes
> parsing and understanding logic tests harder. This is a bad bargain: logic
> tests already contain a lot of complexity that human readers have to cope
> with.
>
> Proponents of := argue it makes several patterns flatter (= better than
> nested)
> to express. Serial regular expression matching is a popular example.
> However,
> (name := expression) itself is making logic tests more nested, not
> flatter. It
> makes information in the logic test denser (= worse than sparse). Since it
> also
> requires an additional pair of parentheses, it forces the reader to
> decompose
> the expression in their head.
>
> := also goes against having one obvious way to do it. Since it's an
> expression,
> it can also be placed on its own line or in otherwise weird places like
> function call arguments. I anticipate PEP 8 would have to be extended to
> explicitly discourage such abuse. Linters would grow rules against it.
> This is
> noise.
>
> I'm -1 on PEP 572, I think it's very similar in spirit to the rejected PEP
> 463.
>
> -- Ł
>
>
> ___
> Python-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] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Chris Angelico
On Thu, Apr 26, 2018 at 6:21 AM, Łukasz Langa  wrote:
> := also goes against having one obvious way to do it. Since it's an 
> expression,
> it can also be placed on its own line or in otherwise weird places like
> function call arguments. I anticipate PEP 8 would have to be extended to
> explicitly discourage such abuse. Linters would grow rules against it. This is
> noise.

Does this argument also apply to the if/else expression? Do linters
need rules to advise against people writing code like:

print(x) if x is None else print(y)

? It's perfectly legal to write code like this. But I don't see people
abusing this sort of thing.

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


[Python-Dev] (name := expression) doesn't fit the narrative of PEP 20

2018-04-25 Thread Łukasz Langa
PEP 572 caused a strong emotional reaction in me. I wanted to first understand
my intuitive objection to the idea before posting anything.

I feel that (name := expression) doesn't fit the narrative of PEP 20. It
doesn't remove complexity, it only moves it. What was its own assignment before
now is part of the logic test. This saves on vertical whitespace but makes
parsing and understanding logic tests harder. This is a bad bargain: logic
tests already contain a lot of complexity that human readers have to cope with.

Proponents of := argue it makes several patterns flatter (= better than nested)
to express. Serial regular expression matching is a popular example. However,
(name := expression) itself is making logic tests more nested, not flatter. It
makes information in the logic test denser (= worse than sparse). Since it also
requires an additional pair of parentheses, it forces the reader to decompose
the expression in their head.

:= also goes against having one obvious way to do it. Since it's an expression,
it can also be placed on its own line or in otherwise weird places like
function call arguments. I anticipate PEP 8 would have to be extended to
explicitly discourage such abuse. Linters would grow rules against it. This is
noise.

I'm -1 on PEP 572, I think it's very similar in spirit to the rejected PEP 463.

-- Ł



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


[Python-Dev] PEP 394 update proposal: Allow changing the `python` command in some cases

2018-04-25 Thread Petr Viktorin

Hello,
In Fedora, I found that PEP 394's strict recommendation that `python` 
points to `python2` is holding us back. From discussions on Zulip and 
elsewhere it's clear that this recommendation is not changing any time 
soon, but I would like to officially relax it in several cases.


The problems are:
- For developers that are not following the language's development, the 
fact that `python` invokes `python2` sends a strong signal that 2 is 
somehow the preferred version, and it's OK to start new projects in it.
- Users and sysadmins that *do* want to “live in the future” are 
switching the symlink to `python3` themselves. We would like to give 
them a supported, documented way to do so -- and make surer they're 
aware of the caveats.
- The `python` command is still not available out-of-the box on macOS, 
so it didn't completely live up to the expectation of being the 
cross-platform way to launch 2/3 source compatile scripts.
- `python` in the shebang line can mean *either* that a script is 
carefully written to be 2/3 compatible, *or* that the author/maintainer 
is lazy or unaware of the recommendations. While Fedora guidelines have 
long banned the unversioned command, we feel that the only way to 
*enforce* that guidelines is to provide environments where the `python` 
command does not work (unless explicitly installed).


To help solve these, I would like to relax recommendations on the Unix 
``python -> python2`` symlink in these cases:


- Users and administrators can, by a deliberate action, change 
``python`` to invoke Python 3. (Activating a venv counts as such an 
action, but so would e.g. using alternates, installing a non-default 
overriding package, or replacing /usr/bin/python.)
- In controlled environments where being explicit is valued more than 
user experience (test environments, build systems, etc.), distributions 
can omit the `python` command even when `python2` is installed.


I have filed these changes as a pull request here:

  https://github.com/python/peps/pull/630

The PR also spells out several other things, which I felt were hidden 
between the lines -- but correct me if you disagree with my reading.

___
Python-Dev mailing list
Python-Dev@python.org
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-25 Thread Petr Viktorin

On 04/25/18 14:46, Jeroen Demeyer wrote:

On 2018-04-25 20:33, Petr Viktorin wrote:

Perhaps "m_objclass" could point to the module in this case


That was exactly my idea also today. Instead of treating m_objclass as 
the defining class, we should generalize it to be the "parent" of the 
function: either the class or the module.


Great to hear we think alike.

However, I think that while reusing the pointer is nice to save space, 
the two concepts should still be separate, because "defining module" is 
a reasonable concept even for methods. In particular:

- There should be *separate* accessor functions for:
  - getting the defining class
  - getting the defining module
- The latter would later (in PEP 573) be extended to return the defining 
module even for class methods (when available)

- In Python code, __objclass__ should be the defining class, not the module.
- The C field should have a different name (m_parent?), so it isn't that 
strongly associated with __objclass__.


Does that sound reasonable?
___
Python-Dev mailing list
Python-Dev@python.org
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-25 Thread Jeroen Demeyer

On 2018-04-25 20:33, Petr Viktorin wrote:

Perhaps "m_objclass" could point to the module in this case


That was exactly my idea also today. Instead of treating m_objclass as 
the defining class, we should generalize it to be the "parent" of the 
function: either the class or the module.


___
Python-Dev mailing list
Python-Dev@python.org
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-25 Thread Petr Viktorin

On 04/24/18 13:12, Jeroen Demeyer wrote:

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.


You're talking about functions with METH_BINDING here, right?
There the other "self" would be the defining module.
It might make sense to pass that also in the struct, rather than as an 
additional argument.
Perhaps "m_objclass" could point to the module in this case, or a new 
pointer could be 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] assignment expressions: an alternative alternative proposal

2018-04-25 Thread Chris Angelico
On Thu, Apr 26, 2018 at 1:46 AM, Guido van Rossum  wrote:
> On Wed, Apr 25, 2018 at 2:27 AM, Steve Holden  wrote:
>>
>> On Wed, Apr 25, 2018 at 6:16 AM, Steven D'Aprano 
>> wrote:
>>>
>>> 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 :-(
>>
>>
>> +1
>
>
> Maybe I should have just said "no". Thanks Steven D'A for saving everyone
> yet another detour on this proposal.
>
> I'm pretty excited myself about NAME :=  and am mostly ignoring
> the current crop of counter-proposal.

Of course, if someone wants to start a python-bad-ideas mailing list,
I'm sure some of these alternatives would be perfect for it...

If anyone hasn't seen the latest iteration of the PEP, I recently
re-posted it. And it's always available here:

https://www.python.org/dev/peps/pep-0572/

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

2018-04-25 Thread Guido van Rossum
On Wed, Apr 25, 2018 at 2:27 AM, Steve Holden  wrote:

> On Wed, Apr 25, 2018 at 6:16 AM, Steven D'Aprano 
> wrote:
>
>> 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 :-(
>>
>
> ​+1
>

Maybe I should have just said "no". Thanks Steven D'A for saving everyone
yet another detour on this proposal.

I'm pretty excited myself about NAME :=  and am mostly ignoring
the current crop of counter-proposal.

-- 
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

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

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

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

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

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

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

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

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

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

- dave
--
"Syntactic sugar causes cancer of the semicolon" - Alan Perlis___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Meta-question about this mailing list

2018-04-25 Thread Stéfane Fermigier
Hi,

the description on https://mail.python.org/mailman/listinfo/python-dev
 reads:

"On this list the key Python developers discuss the future of the language
and its implementation."

I interpret this sentence as "only key (core?) developers are supposed to
participate in the discussion (ie. post messages), the rest is welcome to
lurk."

Is this the intended meaning ?

There is an additional description in the devguide:

"python-dev is the primary mailing list for discussions about Python’s
development. The list is open to the public and is subscribed to by all
core developers plus many people simply interested in following Python’s
development. Discussion is focused on issues related to Python’s
development, such as how to handle a specific issue, a PEP, etc."

I would interpret it as "it's OK for non core developers to post", except
for the "many people simply interested in following Python’s development"
part which hints that we are welcome to "follow" but not actively
participate.

So in either case (and both descriptions) it would IMHO be useful to use
clearer language.


Another point: later in the Mailman description, one reads: "Consider using
Gmane." (with a link to http://dir.gmane.org/gmane.comp.python.devel ).

I went to Gmane and found all the links broken. I remember there was some
turmoil at Gmane a couple of years back:

https://en.wikipedia.org/wiki/Gmane#References

=> It seems the migration didn't work that well and the service shouldn't
been relied upon.

Regards,

  S.








-- 
Stefane Fermigier - http://fermigier.com/ - http://twitter.com/sfermigier -
http://linkedin.com/in/sfermigier
Founder & CEO, Abilian - Enterprise Social Software -
http://www.abilian.com/
Chairman, Free Group @ Systematic Cluster -
http://www.gt-logiciel-libre.org/
Co-Chairman, National Council for Free & Open Source Software (CNLL) -
http://cnll.fr/
Founder & Organiser, PyParis & PyData Paris - http://pyparis.org/ &
http://pydata.fr/
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2018-04-25 Thread Steven D'Aprano
On Tue, Apr 24, 2018 at 11:55:16PM -0700, Nathaniel Smith wrote:

> These examples all make me very nervous. The order of execution in
> comprehensions is pretty confusing to start with (right to left,
> except when it's left to right!).

I don't think comprehensions are ever right to left. With one small 
irregularity, execution follows Python's normal order, namely (mostly) 
left to right except where precedence requires something different, the 
if operator etc.

The one small irregularity is that the values produced by 
the comprehension are written first, rather than last. That is, given:

[expression for item in iterable ...]

the initial expression doesn't get evaluated until the loop is entered. 
But the expression still evaluates in left-to-write order (modulo 
operator precedence etc) and everything following the first "for" 
keywords also evaluates in left-to-right order.


[...]
> Concretely, I find it unnerving that two of these work, and one doesn't:
> 
> # assignment on the right of usage
> results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]

This shouldn't be surprising. We place the expression first because 
that's the most important part of the comprehension, the values it 
generates. Everything from the "for" onwards is just scaffolding needed 
to produce those values, its the leading expression that matters.

But clearly we can't expect to evaluate the expression *before* the 
loop, even though we want it written first. So although the 
comprehension is written expression first, the expression is actually 
evaluated *last*.

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


So when reading a comprehension in execution order:

- look ahead to the first "for" keyword;

- read to the end of the comprehension, using normal left-to-right
  execution order (modulo the usual exceptions);

- jump back to the expression at the start;

- read in normal left-to-right execution order.

So aside from that small anomaly of the expression coming first, 
comprehensions use the same order as regular Python code. Binding 
expressions won't change that.


> I could probably figure it out if necessary, but even in
> simple cases like f(g(), h()), then do you really know for certain off
> the top of your head whether g() or h() runs first?

Of course. Left-to-right execution order (modulo the usual...) is a 
language guarantee.

> Does the average user?

I dare say the average user probably doesn't even think about it, and 
merely assumes that everything is left to right until they learn 
differently. In this case, that reasonable default position is correct. 
Everything is left to right until you learn differently.


> With code like f(a := g(), h(a)) this suddenly matters a lot!

That's hardly different from any other precedence issue, and even when 
precedence is specified by the language, sometimes adding a few extra 
brackets makes things clearer even when they're not needed:

func(arg, (spam*n == token), (a := g()), h(a))


> But comprehensions suffer from a particularly extreme version of this,
> so it worries me that they're being put forward as the first set of
> motivating examples.

Ha, I think that comprehensions are one of the weaker motivating 
examples, but it was a discussion on Python-Ideas about adding special 
syntax *only* to comprehensions which lead to Chris writing the PEP. So 
it is purely an accident of history why comprehensions are the first 
example in the PEP.


> > # Capturing regular expression match objects
> > # See, for instance, Lib/pydoc.py, which uses a multiline spelling
> > # of this effect
> > if match := re.search(pat, text):
> > print("Found:", match.group(0))
> 
> Now this is a genuinely compelling example! re match objects are
> always awkward to work with. But this feels like a very big hammer to
> make re.match easier to use :-). I wonder if there's anything more
> focused we could do here?

A reasonable point.


[...]
> However, I do think it'd be kinda confusing if we had:
> 
> if EXPR as X:
> while EXPR as X:
> with EXPR as X:
> 
> and the first two assign the value of EXPR to X, while the last one
> does something more subtle. Or maybe it'd be fine?

It would be fine, right up to the point that it wasn't, and then it 
would be a brain melting bug magnet that would cause programmers to 
curse us onto the 20th generation.



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


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

2018-04-25 Thread Steve Holden
On Wed, Apr 25, 2018 at 4:56 AM, Tim Peters  wrote:

> [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 ;-)
>
> ​You just don't realise how perspicacious you truly are, Tim!
​


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


​Indeed, in the cases where I currently find myself unwrapping expressions
to capture their values in local variables for debugging purposes it would
usually be far less intrusive to bind a name to the expression inline, then
use the debugger to inspect the value.
​
___
Python-Dev mailing list
Python-Dev@python.org
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-25 Thread Glenn Linderman

On 4/24/2018 6:10 PM, Tim Peters wrote:

Luckily, I only have to write code for me now, so am free to pick the
perfect compromise in every case;-)

QOTD !  I'm in the same situation.
___
Python-Dev mailing list
Python-Dev@python.org
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-25 Thread Steve Holden
On Wed, Apr 25, 2018 at 6:16 AM, Steven D'Aprano 
wrote:

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

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


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

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

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

Restricting the targets in

target := expression

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

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

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


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

2018-04-25 Thread Chris Angelico
On Wed, Apr 25, 2018 at 4:55 PM, Nathaniel Smith  wrote:
> On Tue, Apr 24, 2018 at 8:31 AM, Chris Angelico  wrote:
>> 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.
>
> I haven't read most of the discussion around this, so my apologies if
> I say anything that's redundant. But since it seems like this might be
> starting to converge, I just read through it for the first time, and
> have a few comments.
>
> First, though, let me say that this is a really nice document, and I
> appreciate the incredible amount of work it takes to write something
> like this and manage the discussions! Regardless of the final outcome
> it's definitely a valuable contribution.

Thank you, but I'm hoping to do more than just rejected PEPs. (I do
have one co-authorship to my name, but that was something Guido
started, so it kinda had a bit of an advantage there.) My reputation
as champion of death march PEPs is not something I want to continue.
:|

> Concretely, I find it unnerving that two of these work, and one doesn't:
>
> # assignment on the right of usage
> results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]
>
> # assignment on the left of usage
> stuff = [[y := f(x), x/y] for x in range(5)]
>
> # assignment on the right of usage
> stuff = [[x/y, y := f(x)] for x in range(5)]

Fair point. However, this isn't because of assignment operators, but
because of comprehensions. There are two important constructs in
Python that have out-of-order evaluation:

x if cond else y # evaluates cond before x
[result for x in iterable if cond] # evaluates result last
target()[0] = value # evaluates target after value

... Amongst our weaponry ... err, I'll come in again.

Ahem. Most of Python is evaluated left-to-right, top-to-bottom, just
as anyone familiar with a Latin-derived language would expect. There
are exceptions, however, and those are generally on the basis that
"practicality beats purity". Those exceptions include assignment, the
if/else expression, and comprehensions/genexps. But even within those
constructs, evaluation is left-to-right as much as it possibly can be.
A list comprehension places the target expression first (exception to
the LTR rule), but evaluates all its 'for' and 'if' clauses in order.

We *already* have some strange cases as a result of this out-of-order
evaluation. For instance:

reciprocals = [1/x for x in values if x]

The 'if x' on the right means we won't get a ZeroDivisionError from
the expression on the left. Were this loop to be unrolled, it would
look like this:

def listcomp():
result = []
for x in values:
if x:
result.append(1/x)
return result
reciprocals = listcomp()

And you can easily audit the longhand form to confirm that, yes, "if
x" comes before "1/x". It's the same with assignment expressions; the
only exception to the "left before right" rule is the primary
expression being evaluated after all for/if clauses. Unrolling your
three examples gives (eliding the function wrappers for simplicity):

# assignment on the right of usage
for x in input_data:
if (y := f(x)) > 0:
results.append((x, y, x/y))

# assignment on the left of usage
for x in range(5):
stuff.append([y := f(x), x/y])

# assignment on the right of usage
for x in range(5):
stuff.append([x/y, y := f(x)])

Were list comprehensions *wrong* to put the expression first? I'm not
sure, but I can't see a better way to write them; at best, you'd end
up with something like:

[for x in numbers if x % 2: x * x]

which introduces its own sources of confusion (though I have to say,
it would look pretty clean in the "one for loop, no conditions" case).
But whether they're right or wrong, they're what we have, and side
effects are already legal, and assignment expressions are just another
form of side effect.

> I guess this isn't limited to comprehensions either – I rarely see
> complex expressions with side-effects embedded in the middle, so I'm
> actually a bit hazy about the exact order of operations inside Python
> expressions. I could probably figure it out if necessary, but even in
> simple cases like f(g(), h()), then do you really know for certain off
> the top of your head whether g() or h() runs first? Does the average
> user? With code like f(a := g(), h(a)) this suddenly matters a lot!
> But comprehensions suffer from a particularly extreme version of this,
> so it worries me that they're being put forward as the first set of
> motivating examples.

Honestly, I would fully expect that g() is run first, but I know there
are more complicated cases. For instance, here are three ways to print
"1" followed by "2", and create a dictionary mapping None to None:

>>> x={}
>>> x[print(2)] = print(1)
1
2
>>> x={print(1): print(2)}
1
2
>>> 

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

2018-04-25 Thread Nathaniel Smith
On Tue, Apr 24, 2018 at 8:31 AM, Chris Angelico  wrote:
> 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.

I haven't read most of the discussion around this, so my apologies if
I say anything that's redundant. But since it seems like this might be
starting to converge, I just read through it for the first time, and
have a few comments.

First, though, let me say that this is a really nice document, and I
appreciate the incredible amount of work it takes to write something
like this and manage the discussions! Regardless of the final outcome
it's definitely a valuable contribution.

> Recommended use-cases
> =
>
> Simplifying list comprehensions
> ---
>
> A list comprehension can map and filter efficiently by capturing
> the condition::
>
> results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]
>
> Similarly, a subexpression can be reused within the main expression, by
> giving it a name on first use::
>
> stuff = [[y := f(x), x/y] for x in range(5)]
>
> # There are a number of less obvious ways to spell this in current
> # versions of Python, such as:
>
> # Inline helper function
> stuff = [(lambda y: [y,x/y])(f(x)) for x in range(5)]
>
> # Extra 'for' loop - potentially could be optimized internally
> stuff = [[y, x/y] for x in range(5) for y in [f(x)]]
>
> # Using a mutable cache object (various forms possible)
> c = {}
> stuff = [[c.update(y=f(x)) or c['y'], x/c['y']] for x in range(5)]
>
> In all cases, the name is local to the comprehension; like iteration 
> variables,
> it cannot leak out into the surrounding context.

These examples all make me very nervous. The order of execution in
comprehensions is pretty confusing to start with (right to left,
except when it's left to right!). But usually this is fine, because
comprehensions are mostly used in a functional/declative-ish style,
where the exact order doesn't matter. (As befits their functional
language heritage.) But := is a side-effecting operator, so when you
start using it here, I suddenly have to become extremely aware of the
exact order of execution.

Concretely, I find it unnerving that two of these work, and one doesn't:

# assignment on the right of usage
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]

# assignment on the left of usage
stuff = [[y := f(x), x/y] for x in range(5)]

# assignment on the right of usage
stuff = [[x/y, y := f(x)] for x in range(5)]

I guess this isn't limited to comprehensions either – I rarely see
complex expressions with side-effects embedded in the middle, so I'm
actually a bit hazy about the exact order of operations inside Python
expressions. I could probably figure it out if necessary, but even in
simple cases like f(g(), h()), then do you really know for certain off
the top of your head whether g() or h() runs first? Does the average
user? With code like f(a := g(), h(a)) this suddenly matters a lot!
But comprehensions suffer from a particularly extreme version of this,
so it worries me that they're being put forward as the first set of
motivating examples.

> Capturing condition values
> --

Note to Chris: your examples in this section have gotten their order
scrambled; you'll want to fix that :-). And I'm going to reorder them
yet again in my reply...

> # Reading socket data until an empty string is returned
> while data := sock.read():
> print("Received data:", data)

I don't find this example very convincing. If it were written:

for data in iter(sock.read, b""):
...

then that would make it clearer what's happening ("oh right, sock.read
uses b"" as a sentinel to indicate EOF). And the fact that this is
needed at all is only because sockets are a low-level API with lots of
complexity inherited from BSD sockets. If this were a normal python
API, it'd just be

for data in sock:
...

(Hmm, I guess the original example is actually wrong because it should
be sock.recv, and recv takes a mandatory argument. To be fair, adding
that argument would also make the iter() version uglier, and that
argument explains why we can't support 'for data in sock'. But this is
still consistent with my argument that working directly with sockets
is always going to be a bit awkward... I don't think bits of sugar
like this are going to make any substantive difference to how easy it
is read or write raw socket code.)

> # Proposed syntax
> while (command := input("> ")) != "quit":
> print("You entered:", command)
>
> # Equivalent in current Python, not caring about function return value
> while input("> ") != "quit":
> print("You entered a command.")
>
> # To capture the return value in current Python 

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

2018-04-25 Thread Glenn Linderman

On 4/24/2018 8:56 PM, Tim Peters wrote:

  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've done both subexpression mangling (attempts at duplication) and 
added print statements and experienced these negative side effects, 
taking twice as long (or more) as intended to get the debugging 
information needed.


While I'm no core developer, and would have a mild appreciation of 
avoiding those while True: loops so was generally in favor of this PEP, 
but not enough to be inpsired to speak up about it, I would frequently 
benefit from this capability... adding extra binding names, and printing 
_them_ instead of the duplicated subexpressions.


+1

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