[Python-Dev] Informal educator feedback on PEP 572 (was Re: 2018 Python Language Summit coverage, last part)

Chris Barker chris.barker at noaa.gov
Thu Jun 28 18:42:49 EDT 2018

On Thu, Jun 28, 2018 at 9:28 AM, Tim Peters <tim.peters at gmail.com> wrote:

> >>> g = (x:=i for i in range(3))
> Common or not, I have no idea why anyone would write a genexp like the one
> you gave, except to contrive an example of silly behavior exhibited by
> silly code ;-)

yes, it was a contrived example, but the simplest one I could think of off
the top of my head that re-bound a name in the loop -- which was what I
thought was the entire point of this discussion?

If we think hardly anyone is ever going to do that -- then I guess it
doesn't matter how it's handled.

> So while this is technically the same as the comprehension, it is not
> > the same as a generator function which does get its own scope.
> It is the same as a generator function with appropriate scope declarations
> - a generator expression is, after all, implemented _by_ a nested generator
> function.  You can write a workalike to your code above today, but nobody
> worries about that because nobody does that ;-)
>     def f():
>         def bashx(outermost):
>             nonlocal x
>             for i in outermost:
>                 x = i
>                 yield i

but here the keyword "nonlocal" is used -- you are clearly declaring that
you are messing with a nonlocal name here -- that is a lot more obvious
than simply using a :=

And "nonlocal" is not used that often, and when it is it's for careful
closure trickery -- I'm guessing := will be far more common. And, of
course, when a newbie encounters it, they can google it and see what it
means -- far different that seeing a := in a comprehension and
understanding (by osmosis??) that it might make changes in the local scope.

And  I don't think you can even do that with generator expressions now --
as they can only contain expressions. Which is my point -- this would allow
the local namespace to be manipulated in places it never could before.

Maybe it's only comprehensions, and maybe it'll be rare to have a confusing
version of those, so it'll be no big deal, but this thread started talking
about educators' take on this -- and as an educator, I think this really
does complicate the language.

Python got much of it's "fame" by being "executable pseudo code" -- its
been moving farther and farther away from those roots. That's generally a
good thing, as we've gain expressiveness in exchangel, but we shouldn't
pretend it isn't happening, or that this proposal doesn't contribute to
that trend.

Did adding ternary `if` (truepart if expression else falsepart) complicate
> the language significantly?

I don't think so -- no. For two reasons:

1) the final chosen form is kind of verbose, but therefor more like
"executable pseudo code" :-) As apposed to the C version, for instance.

2) it added one new construct, that if, when someone sees it for the first
(or twenty fifth) time and doesn't understand it, they can look it up, and
find out. and it only effects that line of code.

So adding ANYTHING does complicate the language, by simply making it a bit
larger, but some things are far more complicating than others.

Python has rarely expanded the number of expression forms, but whenever it
> has the sky didn't actually fall despite earnest warnings that disaster was
> inevitable ;-)

Well, I've been surprised by what confused students before, and I will
again. But I dont hink there is any doubt that Python 3.7 is a notably
harder to learn that Python 1.5 was...

> > Maybe it’s just me, but re-binding a name seems like a whole new
> > category of side effect.
> With no trickery at all, you've always been able to rebind attributes, and
> mutate containers, in comprehensions and genexps.  Because `for` targets
> aren't limited to plain names; e.g.,
>     g = (x+y for object.attribute, a[i][j] in zip(range(3), range(3)))

sure, but you are explicitly using the names "object" and "a" here -- so
while side effects in comprehension are discouraged, it's not really a
surprised that namespaces specifically named are changed.

and this:

In [*55*]: x = 0

In [*56*]: [x *for* x *in* range(3)]

Out[*56*]: [0, 1, 2]

In [*57*]: x

Out[*57*]: 0

doesn't change x in the local scope -- if that was a good idea, why is a
good idea to have := in a comprehension effect the local scope??

But maybe it is just me.

> And as in my goofy code above, mucking with binding of plain names is also
> possible today.  Indeed, straightforward if that's what you _want_ to do.
> But nobody does.
> It's just not one of Python's goals to make it impossible to write useless
> code ;-)

 I suppose we need to go back and look at the "real" examples of where/how
folks think they'll use := in comprehensions, and see how confusing it may

One of these conversations was started with an example something like this:

[(f(x), g(f(x))) for x in an_iterable]

The OP didn't like having to call f() twice. So that would become:

[ (temp:=f(x), g(temp)) for x in an_iterable]

so now the question is: should "temp" be created / changed in the enclosing
local scope?

This sure looks a lot like letting the iteration name (x in this example)
leak out -- so I'd say no.

And I don't think this kind of thing would be rare.

Someone mentions that one problem with letting the iteration name leak out
is that people tend to use short, common names, like "i" -- Im thinking
that would also be the case for this kind of temp variable.



Christopher Barker, Ph.D.

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.Barker at noaa.gov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180628/b7aa4c36/attachment.html>

More information about the Python-Dev mailing list