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

Tim Peters tim.peters at gmail.com
Thu Jun 28 12:28:10 EDT 2018


[Chris Barker]
>>> So what about:
>>>
>>> l = [x:=i for i in range(3)]
>>>
>>> vs
>>>
>>> g = (x:=i for i in range(3))
>>>
>>> Is there any way to keep these consistent if the "x" is in the regular
local scope?

[Tim]
>> I'm not clear on what the question is.  The list comprehension would
>> bind ` l ` to [0, 1, 2] and leave the local `x` bound to 2.  The second
>> example binds `g` to a generator object, which just sits there
>> unexecuted.  That has nothing to do with the PEP, though.
>>
>> If you go on to do, e.g.,
>>
>> l = list(g)
>>
>> then, same as the listcomp, `l` will be bound to [0, 1, 2] and the local
`x` will
>> be left bound to 2.

[Chris]
> OK, it has been said that the priority is that
>
> list(a_gen_expression)
>
> Behave the same as
>
> [the_same_expression]

That's certainly desirable.


> So we’re good there. And maybe it’s  correct that leaving the running
> of the gen_exp ‘till later is pretty uncommon, particularly for newbies,

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

It's really not interesting to me to make up code as goofy as you can
conceive of - the interesting questions are about plausible code (including
plausible coding errors).

>  but:
>
> If the execution of the gen_exp is put off, it really confuses things
> — that name being changed would happen at some arbitrary tone, and at
> least in theory, the gen_exp could be passed off to somewhere else in
> the code, and be run or not run completely remotely from where the
> name is used.

Sure.

> 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

        x = 12
        g = bashx(range(3))
        print("x before", x)
        L = list(g)
        print("L", L)
        print("x after", x)

Then calling `f()` prints:

    x before 12
    L [0, 1, 2]
    x after 2

> And we should be clear how it will work — after all, in py2, the
> handling of the looping name was handled differently in gen_exp vs
> comprehensions.

The PEP specifies the semantics.  If it's accepted, that will be folded
into the docs.

> So I think a local scope for all comprehension-like things would be
> the way to go.
>
> But getting back to the original thread topic — python has a number of
> places that you can only use expressions — adding the ability to bind
> a name in all these places complicates the language significantly.

Did adding ternary `if` (truepart if expression else falsepart) complicate
the language significantly?  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 ;-)

>>   Put a body B in a listcomp and any side effects due to executing B

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

is already "legal", and will stomp all over the complex `for` targets when
executed - there's nothing "local" about them.  But nobody worries about
that because nobody does stuff like that.

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 ;-)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180628/63716a34/attachment.html>


More information about the Python-Dev mailing list