[Python-Dev] PEP 572: Assignment Expressions

Guido van Rossum guido at python.org
Wed Apr 18 09:58:37 EDT 2018


On Tue, Apr 17, 2018 at 7:04 PM, Chris Angelico <rosuav at gmail.com> wrote:

> On Wed, Apr 18, 2018 at 11:20 AM, Steven D'Aprano <steve at pearwood.info>
> wrote:
> > On Wed, Apr 18, 2018 at 10:13:58AM +1000, Chris Angelico wrote:
> >
> > [regarding comprehensions]
> >
> >> The changes here are only to edge and corner cases, other than as they
> >> specifically relate to assignment expressions. The current behaviour
> >> is intended to "do the right thing" according to people's
> >> expectations, and it largely does so; those cases are not changing.
> >> For list comprehensions at global or function scope, the ONLY case
> >> that can change (to my knowledge) is where you reuse a variable name:
> >>
> >> [t for t in t.__parameters__ if t not in tvars]
> >>
> >> This works in 3.7 but will fail easily and noisily (UnboundLocalError)
> >> with PEP 572.
> >
> > That's a major semantic change, and the code you show is no better or
> > worse than:
> >
> >     t = ...
> >     result = []
> >     for t in t.parameters:
> >         if t not in tvars:
> >             result.append(t)
> >
> >
> > which is allowed. I think you need a better justification for breaking
> > it than merely the opinion:
> >
> >> IMO this is a poor way to write a loop,
>
> Ah but that isn't what the list comp is equivalent to. If you want to
> claim that "for t in t.parameters" is legal, you first have to assume
> that you're overwriting t, not shadowing it. In the list comp as it is
> today, the "for t in" part is inside an implicit nested function, but
> the "t.parameters" part is outside that function.
>
> Try this instead:
>
> t = ...
> def listcomp():
>     result = []
>     for t in t.parameters:
>         if t not in tvars:
>             result.append(t)
>     return result
> listcomp()
>
> Except that it isn't that either, because the scope isn't quite that
> clean. It actually involves a function parameter, and the iterator is
> fetched before it's passed as a parameter, and then NOT fetched inside
> the loop. So you actually can't write perfectly equivalent longhand.
>
> PEP 572 will *reduce* the edge cases and complexity.


I can't tell from this what the PEP actually says should happen in that
example. When I first saw it I thought "Gaah! What a horrible piece of
code." But it works today, and people's code *will* break if we change its
meaning.

However we won't have to break that. Suppose the code is (perversely)

t = range(3)
a = [t for t in t if t]

If we translate this to

t = range(3)
def listcomp(t=t):
    a = []
    for t in t:
        if t:
            a.append(t)
    return a
a = listcomp()

Then it will still work. The trick will be to recognize "imported" names
that are also assigned and capture those (as well as other captures as
already described in the PEP).

-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180418/616876d9/attachment.html>


More information about the Python-Dev mailing list