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

2018-04-19 Thread Nick Coghlan
On 19 April 2018 at 02:18, Guido van Rossum  wrote:
> On Wed, Apr 18, 2018 at 7:35 AM, Chris Angelico  wrote:
>>
>> On Wed, Apr 18, 2018 at 11:58 PM, Guido van Rossum 
>> wrote:
>> 2) Genexps will eagerly evaluate a lookup if it happens to be the same
>> name as an internal iteration variable.
>
> I think we would have to specify this more precisely.
>
> Let's say by "eagerly evaluate a lookup" you mean "include it in the
> function parameters with a default value being the lookup (i.e. starting in
> the outer scope), IOW "t=t" as I showed above. The question is *when* we
> would do this. IIUC the PEP already does this if the "outer scope" is a
> class scope for any names that a simple static analysis shows are references
> to variables in the class scope. (I don't know exactly what this static
> analysis should do but it could be as simple as gathering all names that are
> assigned to in the class, or alternatively all names assigned to before the
> point where the comprehension occurs. We shouldn't be distracted by dynamic
> definitions like `exec()` although we should perhaps be aware of `del`.)
>
> My proposal is to extend this static analysis for certain loop control
> variables (any simple name assigned to in a for-clause in the
> comprehension), regardless of what kind of scope the outer scope is. If the
> outer scope is a function we already know how to do this. If it's a class we
> use the analysis referred to above. If the outer scope is the global scope
> we have to do something new. I propose to use the same simple static
> analysis we use for class scopes.
>
> Furthermore I propose to *only* do this for the loop control variable(s) of
> the outermost for-clause, since that's the only place where without all this
> rigmarole we would have a clear difference in behavior with Python 3.7 in
> cases like [t for t in t]. Oh, and probably we only need to do this if that
> loop control variable is also used as an expression in the iterable (so we
> don't waste time doing any of this for e.g. [t for t in q]).

I'm not sure the symtable pass is currently clever enough to make
these kinds of distinctions - it's pretty thoroughly block scope
oriented. (Although I guess it *does* know enough now to treat the
outermost comprehension as being part of the surrounding scope in
terms of where names are referenced, so it might be feasible to adapt
that logic to enable the eager binding you're describing).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2018-04-19 Thread Nick Coghlan
On 19 April 2018 at 02:38, Brett Cannon  wrote:
> I'm also -1.
>
> I understand the usefulness of the construct in languages where block scopes
> make having this kind of expression assignment in e.g. an 'if' guard useful.
> But for Python and it's LGB scoping -- although I think we need to add an
> "N" for "non-local" :) -- this is syntactic sugar and I don't see enough
> wide benefit on top of the potential ugliness/misuse of it to warrant the
> cognitive overhead of adding it.
>
> Although, as usual, Chris, great PEP! :)

Aye, tremendous work on the PEP Chris - assignment expressions are an
idea that has come up many, many times on python-ideas, and it's great
to finally have a consolidated proposal that attempts to make the best
case it can for the idea.

Unfortunately, I still have to admit that even I'm -0 on the idea of
actually adding it to the language (despite helping it to reach a
plausibly acceptable state), primarily on "more than one way to do it"
grounds:

* assignment statements and top-level assignment expressions would be
syntactically distinct, but semantically identical
* for the if statement use case, pre-assignment of the re-used part of
the condition expression already works fine
* for the while loop use case, I think my discussion with Tim about
tuple unpacking shows that the loop-and-a-half construct won't be
going anywhere, so users would still end up needing to learn both
forms (even for new code)

The comprehension/genexp use case still seems like the most promising
candidate for a reasonable justification for the extra complexity, but
there's also a solid argument that if a comprehension is complex
enough that the lack of assignment expressions is causing problems,
then it's also complex enough that it's reasonable to require
extracting the algorithm into a named generator function in order to
access assignment statements.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2018-04-19 Thread Chris Barker
On Thu, Apr 19, 2018 at 5:45 AM, Nick Coghlan  wrote:

> * for the while loop use case, I think my discussion with Tim about
> tuple unpacking shows that the loop-and-a-half construct won't be
> going anywhere, so users would still end up needing to learn both
> forms (even for new code)
>

well, yes, but I've always found while awkward in the common case -- and
wanted a better way (maybe an until?).

using:

while True:
   ...

for a loop with a clear testable termination criteria always felt clunky.

Anyone recall the "canonical" way to loop through the lines of a file
before we had the file iterator?

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


This is in fact, the only compeling use case for this to me -- maybe we
could make a way to do an assign and test in a while loop enhancement just
for that?

And no, I have no idea what that would look like -- I'm mostly joking.

So -1 on this -- though I agree -- great PEP Chris!

And -1, not -0 because I think this really would add one more complication
to a language that used to be so simple, and still is (and should be) used
a first programming language. I teach a lot of newbies, and I'm realy not
l;ooking forward to one more way to do assignement. It starts simpel enough:

x = something

binds the name, "x" the the object, 'something' is bound to (or a literal)

Then we get into:
 - multiple assignment
 - tuple unpacking (oops, sequence unpacking),
 - augmented assignment
 - oh, that works different depending on whether the object is mutable

We don't need any more.

-CHB


-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

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


[Python-Dev] PEP 572: Assignment Expressions

2018-04-19 Thread Christoph Groth
I'd like to break a lance for PEP 572.

I read that in the bad old days Python used to have a "=" operator in
expressions that had the meaning of today's "==".  Perhaps there were
other reasons, but this choice alone meant that assignment (that was
using the same token) could not be made an expression.

When the equality comparison operator was changed to "==", nothing
changed for assignments which remained statements.

Let's imagine, just for a moment, that Python is redesigned from
scratch.  Would it make sense to make assignment an expression? (For
clarity an operator that is different from "=" would be used, say ":=".)

I would say that the answer to the above question depends on whether
assignment expressions can (a) fully replace assignment statements
(so that both don't need to coexist) and (b) are useful and not too
prone to abuse.  I will try to answer both questions separately.



It seems to me that assignment expressions can be defined in a way that
is fully analogous with the assignment statements of today's Python (and
that consequently is equivalent in confusion potential):

The "value" of any assignment statement from today's Python can be
defined as the value that will be captured when "__value__ =" is prepended
to that statement.

So what should be the value of 'result' after the following snippet?

a := list()
b := list()
result := (a[:] := b[:] := iter(range(3)))

It seems to me that it should be the same as with today's

result = a[:] = b[:] = iter(range(3))

Accepting this convention would mean that parens in assignment
expressions would behave differently from C.  For example

result := (a[:] := (b[:] := iter(range(3

would produce a different 'result'.  But I think that's OK, just like
it's OK that the Python expression

-1 < 0 < 1

is not equivalent to

(-1 < 0) < 1



The question remains whether assignment expressions are actually useful
and not too prone to abuse?  I think that the situation is similar to
the "or" and "and" operators when used for their values.  The snippet

value = dic.get(key) or default

could be replaced by an if clause, so there's no "one obvious way to do
it" here.  Still, many will agree that the above one-liner is nicer and
more expressive.  It wouldn't be possible if there were no boolean
expressions and the use of "or" was limited to within if and while
statements.

In a similar way assignment expressions have many uses that are not
absolutely needed but make code more expressive.  The danger of abuse is
also similar to "and" and "or" where it's also possible to write
expressions that are difficult to understand.

Here's an example from real life where the existence of assignment
expressions would crucially simplify an API.  I'm working on a library
that has "learners" that are driven by "runners".  The simplest possible
synchronous runner looks like this:

def sync_runner(learner, f, static_hint):
while True:
points = learner.get(static_hint)
if not points:
break
learner.feed(f(points))

(Note that more advanced runners supply a "hint" that dynamically
depends on currently available resources for example.)

With assignment expressions the body of the above function could be
simplified to

while points := learner.get(static_hint):
learner.feed(f(points))

making it crucially simpler.  Using the learner API becomes so natural
that a 'sync_runner()' function seems not even necessary.  This API
could be even adopted by other learner-providing libraries that want to
support being driven by advanced asynchronous runners but would like to
remain easily usable directly.

Surely there are other uses of similar idioms.



Perhaps you agree with me that assignment should be an expression if
Python was to be redesigned from scratch, but that is not going to
happen.  But couldn't Python simply introduce ":=" as described above
and keep "=" for backwards compatibility?

New users of Python could by taught to use ":=" everywhere.  Old users
could either convert their code base, or ignore the addition.  There's
no problem in mixing both old and new style code.

Like with other expressive features, there's potential for confusion,
but I think that it's limited.  Wouldn't it be a pity not to liberate
assignments from their boring statement existence?

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


[Python-Dev] PEP 572: Now with 25% less reference implementation!

2018-04-19 Thread Chris Angelico
Working on the reference implementation for PEP 572 is turning out to
be a massive time sink, both on my personal schedule and on the PEP's
discussion. I can't just hold off all discussion on a topic until I
figure out whether something is possible or not, because that could
take me several days, even a week or more. And considering the massive
backlash against the proposal, it seems like a poor use of my time to
try to prove that something's impossible, find that I don't know
enough about grammar editing to be able to say anything more than
"well, I couldn't do it, but someone else might be able to", and then
try to resume the discussion with no more certainty than we had
before.

So here's the PEP again, simplified. I'm fairly sure it's just going
to be another on a growing list of rejected PEPs to my name, and I'm
done with trying to argue some of these points. Either the rules get
simplified, or they don't. Trying to simplify the rules and maintain
perfect backward compatibility is just making the rules even more
complicated.

PEP 572, if accepted, *will* change the behaviour of certain
constructs inside comprehensions, mainly due to interactions with
class scope that make no sense unless you know how they're implemented
internally. The official tutorial pretends that comprehensions are
"equivalent to" longhand:

https://docs.python.org/3/tutorial/datastructures.html?highlight=equivalent#list-comprehensions
https://docs.python.org/3/howto/functional.html?highlight=equivalent#generator-expressions-and-list-comprehensions

and this is an inaccuracy for the sake of simplicity. PEP 572 will
make this far more accurate; the only difference is that the
comprehension is inside a function. Current semantics are far more
bizarre than that.

Do you want absolutely 100% backward compatibility? Then reject this
PEP. Or better still, keep using Python 3.7, and don't upgrade to 3.8,
in case something breaks. Do you want list comprehensions that make
better sense? Then accept that some code will need to change, if it
tried to use the same name in multiple scopes, or tried to use ancient
Python 2 semantics with a yield expression in the outermost iterable.

I'm pretty much ready for pronouncement.

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

ChrisA

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


Abstract


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


Rationale
=

Naming the result of an expression is an important part of programming,
allowing a descriptive name to be used in place of a longer expression,
and permitting reuse.  Currently, this feature is available only in
statement form, making it unavailable in list comprehensions and other
expression contexts.  Merely introducing a way to assign as an expression
would create bizarre edge cases around comprehensions, though, and to avoid
the worst of the confusions, we change the definition of comprehensions,
causing some edge cases to be interpreted differently, but maintaining the
existing behaviour in the majority of situations.


Syntax and semantics


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

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

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

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

# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]


Differences from regular assignment statements
--

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

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

x = y = z = 0

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

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

Augmented assignment is not supported in expression form::

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

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


Alterations to co

[Python-Dev] PEP 572: Assignment Expressions

2018-04-19 Thread Stephen J. Turnbull
Christoph Groth writes:

 > Wouldn't it be a pity not to liberate assignments from their boring
 > statement existence?

Maybe not.  While it would be nice to solve the loop-and-a-half
"problem" and the loop variable initialization "problem" (not everyone
agrees these are even problems, especially now that we have
comprehensions and generator expressions), as a matter of taste I like
the fact that this particular class of side effects is given weighty
statement syntax rather than more lightweight expression syntax.

That is, I find statement syntax more readable.

Steve

-- 
Associate Professor  Division of Policy and Planning Science
http://turnbull/sk.tsukuba.ac.jp/ Faculty of Systems and Information
Email: turnb...@sk.tsukuba.ac.jp   University of Tsukuba
Tel: 029-853-5175 Tennodai 1-1-1, Tsukuba 305-8573 JAPAN
___
Python-Dev mailing list
Python-Dev@python.org
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: Now with 25% less reference implementation!

2018-04-19 Thread Dmitry Malinovsky
Hello Chris, and thank you for working on this PEP!

What do you think about using variable type hints with this syntax?
I tried to search through python-dev and couldn't find a single post
discussing that question.
If I missed it somehow, could you please include its conclusions into the PEP?

For instance, as I understand now the parser will fail on this snippet:

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

Do brackets help?

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

IIUC, in 3.7 It is invalid syntax to specify a type hint for a for loop item;
should brackets help? Currently they don't:

Python 3.7.0b3+ (heads/3.7:7dcfd6c, Mar 30 2018, 21:30:34)
[Clang 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> for (x: int) in [1,2,3]:
  File "", line 1
for (x: int) in [1,2,3]:
  ^
SyntaxError: invalid syntax

Thanks,

> On 20 Apr 2018, at 09:10, Chris Angelico  wrote:
> 
> Working on the reference implementation for PEP 572 is turning out to
> be a massive time sink, both on my personal schedule and on the PEP's
> discussion. I can't just hold off all discussion on a topic until I
> figure out whether something is possible or not, because that could
> take me several days, even a week or more. And considering the massive
> backlash against the proposal, it seems like a poor use of my time to
> try to prove that something's impossible, find that I don't know
> enough about grammar editing to be able to say anything more than
> "well, I couldn't do it, but someone else might be able to", and then
> try to resume the discussion with no more certainty than we had
> before.
> 
> So here's the PEP again, simplified. I'm fairly sure it's just going
> to be another on a growing list of rejected PEPs to my name, and I'm
> done with trying to argue some of these points. Either the rules get
> simplified, or they don't. Trying to simplify the rules and maintain
> perfect backward compatibility is just making the rules even more
> complicated.
> 
> PEP 572, if accepted, *will* change the behaviour of certain
> constructs inside comprehensions, mainly due to interactions with
> class scope that make no sense unless you know how they're implemented
> internally. The official tutorial pretends that comprehensions are
> "equivalent to" longhand:
> 
> https://docs.python.org/3/tutorial/datastructures.html?highlight=equivalent#list-comprehensions
> https://docs.python.org/3/howto/functional.html?highlight=equivalent#generator-expressions-and-list-comprehensions
> 
> and this is an inaccuracy for the sake of simplicity. PEP 572 will
> make this far more accurate; the only difference is that the
> comprehension is inside a function. Current semantics are far more
> bizarre than that.
> 
> Do you want absolutely 100% backward compatibility? Then reject this
> PEP. Or better still, keep using Python 3.7, and don't upgrade to 3.8,
> in case something breaks. Do you want list comprehensions that make
> better sense? Then accept that some code will need to change, if it
> tried to use the same name in multiple scopes, or tried to use ancient
> Python 2 semantics with a yield expression in the outermost iterable.
> 
> I'm pretty much ready for pronouncement.
> 
> https://www.python.org/dev/peps/pep-0572/
> 
> ChrisA
> 
> PEP: 572
> Title: Assignment Expressions
> Author: Chris Angelico 
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 28-Feb-2018
> Python-Version: 3.8
> Post-History: 28-Feb-2018, 02-Mar-2018, 23-Mar-2018, 04-Apr-2018, 17-Apr-2018
> 
> 
> Abstract
> 
> 
> This is a proposal for creating a way to assign to variables within an
> expression. Additionally, the precise scope of comprehensions is adjusted, to
> maintain consistency and follow expectations.
> 
> 
> Rationale
> =
> 
> Naming the result of an expression is an important part of programming,
> allowing a descriptive name to be used in place of a longer expression,
> and permitting reuse.  Currently, this feature is available only in
> statement form, making it unavailable in list comprehensions and other
> expression contexts.  Merely introducing a way to assign as an expression
> would create bizarre edge cases around comprehensions, though, and to avoid
> the worst of the confusions, we change the definition of comprehensions,
> causing some edge cases to be interpreted differently, but maintaining the
> existing behaviour in the majority of situations.
> 
> 
> Syntax and semantics
> 
> 
> In any context where arbitrary Python expressions can be used, a **named
> expression** can appear. This is of the form ``target := expr`` where
> ``expr`` is any valid Python expression, and ``target`` is any valid
> assignment target.
> 
> The value of such a named expression is the same as the incorporated
> expression, with the additional s

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

2018-04-19 Thread Chris Barker - NOAA Federal
> On Apr 19, 2018, at 4:27 PM, Christoph Groth  wrote:



> def sync_runner(learner, f, static_hint):
>while True:
>points = learner.get(static_hint)
>if not points:
>break
>learner.feed(f(points))
>
>
>
> With assignment expressions the body of the above function could be
> simplified to
>
> while points := learner.get(static_hint):
>learner.feed(f(points))
>
> making it crucially simpler.

Kinda supports my assertion that what we really want is a different while loop.

Would it be ridiculous if := only worked in a while statement?

-CHB
___
Python-Dev mailing list
Python-Dev@python.org
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: Now with 25% less reference implementation!

2018-04-19 Thread Chris Angelico
On Fri, Apr 20, 2018 at 2:45 PM, Dmitry Malinovsky  wrote:
> Hello Chris, and thank you for working on this PEP!
>
> What do you think about using variable type hints with this syntax?
> I tried to search through python-dev and couldn't find a single post
> discussing that question.
> If I missed it somehow, could you please include its conclusions into the PEP?

I'm ignoring them for the sake of the PEP, because it'd complicate the
grammar for little benefit. If someone wants to add an enhancement
later, that's fine; but the proposal can stand without it, and with
it, it'll make for even more noise in a line full of colons.

> For instance, as I understand now the parser will fail on this snippet:
>
> while data: bytes := stream.read():
> print("Received data:", data)
>
> Do brackets help?
>
> while (data: bytes := stream.read()):
> print("Received data:", data)
>
> IIUC, in 3.7 It is invalid syntax to specify a type hint for a for loop item;
> should brackets help? Currently they don't:
>
> Python 3.7.0b3+ (heads/3.7:7dcfd6c, Mar 30 2018, 21:30:34)
> [Clang 9.0.0 (clang-900.0.39.2)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.
> >>> for (x: int) in [1,2,3]:
>   File "", line 1
> for (x: int) in [1,2,3]:
>   ^
> SyntaxError: invalid syntax

And that's another good reason not to bother, at least for now. I'm
not sure whether you can use a Py2-style type hint comment on a for
loop, but if so, you should also be able to do it on a while loop or
anything. Or, of course, you can just annotate the variable before the
loop, if you want to.

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


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

2018-04-19 Thread Robert Smallshire
If you restrict the idea to 'if' and 'while', Why not render this using the
existing 'as' form for binding names, already used with 'except' and 'with':

while learner.get(static_hint) as points:
learner.feed(f(points))

The equivalent for 'if' helps with the regex matching case:

if re.match(r"...") as m:
print(m.group(1))

I considered proposing these two forms in a PEP a few years ago, but never
got around to it. To my eye, they fit syntactically into the language
as-is, without introducing new symbols, operators or keywords, are
consistent with existing usage, and address two relatively common causes of
displeasing Python code.

Robert
___
Python-Dev mailing list
Python-Dev@python.org
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-19 Thread Chris Angelico
On Fri, Apr 20, 2018 at 1:30 PM, Stephen J. Turnbull
 wrote:
> Christoph Groth writes:
>
>  > Wouldn't it be a pity not to liberate assignments from their boring
>  > statement existence?
>
> Maybe not.  While it would be nice to solve the loop-and-a-half
> "problem" and the loop variable initialization "problem" (not everyone
> agrees these are even problems, especially now that we have
> comprehensions and generator expressions), as a matter of taste I like
> the fact that this particular class of side effects is given weighty
> statement syntax rather than more lightweight expression syntax.
>
> That is, I find statement syntax more readable.
>

If you've read the PEP, you'll see that it encourages the use of
assignment statements whereever possible. If statement syntax is
generally more readable, by all means, use it. That doesn't mean there
aren't situations where the expression syntax is FAR more readable.

Tell me, is this "more readable" than a loop with an actual condition in it?

def sqrt(n):
guess, nextguess = 1, n
while True:
if math.isclose(guess, nextguess): return guess
guess = nextguess
nextguess = n / guess

Readable doesn't mean "corresponds closely to its disassembly",
despite the way many people throw the word around. It also doesn't
mean  "code I like", as opposed to "code I don't like". The words for
those concepts are "strongly typed" and "dynamically typed", as have
been demonstrated through MANY online discussions. (But I digress.)
Readable code is code which expresses an algorithm, expresses the
programmer's intent. It adequately demonstrates something at a
*higher* abstraction level. Does the algorithm demonstrated here
include an infinite loop? No? Then it shouldn't have "while True:" in
it.

Now, this is a pretty obvious example. I deliberately wrote it so you
could simply lift the condition straight into the while header. And I
hope that everyone here agrees that this would be an improvement:

def sqrt(n):
guess, nextguess = 1, n
while not math.isclose(guess, nextguess):
guess = nextguess
nextguess = n / guess
return guess

But what if the condition were more complicated?

def read_document(file):
doc = ""
while (token := file.get_next_token()) != "END":
doc += token
return doc

The loop condition is "while the token is not END", or "while
get_next_token() doesn't return END", depending on your point of view.
Is it "more readable" to put that condition into the while header, or
to use an infinite loop and a break statement, or to duplicate a line
of code before the loop and at the bottom of the loop? Which one best
expresses the programmer's intention?

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


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

2018-04-19 Thread Chris Angelico
On Fri, Apr 20, 2018 at 4:32 PM, Robert Smallshire  wrote:
> If you restrict the idea to 'if' and 'while', Why not render this using the
> existing 'as' form for binding names, already used with 'except' and 'with':
>
> while learner.get(static_hint) as points:
> learner.feed(f(points))
>
> The equivalent for 'if' helps with the regex matching case:
>
> if re.match(r"...") as m:
> print(m.group(1))
>
> I considered proposing these two forms in a PEP a few years ago, but never
> got around to it. To my eye, they fit syntactically into the language as-is,
> without introducing new symbols, operators or keywords, are consistent with
> existing usage, and address two relatively common causes of displeasing
> Python code.

And are limited to conditions that check the truthiness/falsiness of
the value you care about. So that works for re.match, but not for
anything that might return -1 (a lot of C APIs do that, so if you're
working with a thin wrapper, that might be all you get), and it'll
encourage people to use this form when "is not None" would be more
appropriate (setting up for a failure if ever the API returned a
falsey value), etc. It's similar if you use iter(func, None) - it's
actually doing an equality check, not an identity check, even though a
longhand form would be better written with "is not None".

Also, are you assuming that this is binding to a name, or can it
assign to other targets?

if re.match(...) as m[3]:
   ...

HINT: Saying "it should do whatever except and with do" won't answer
the question. Give it a try if you don't believe me. :)

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