osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


On 25.06.2018 14:44, Nick Coghlan wrote:
> On 25 June 2018 at 02:24, Guido van Rossum <guido at python.org> wrote:
>> A quick follow-up: PEP 572 currently has two ideas: (a) introduce := for
>> inline assignment, (b) when := is used in a comprehension, set the scope for
>> the target as if the assignment occurred outside any comprehensions. It
>> seems we have more support for (a) than for (b) -- at least Nick and Greg
>> seem to be +0 or better for (a)
> Right, the proposed blunt solution to "Should I use 'NAME = EXPR' or
> 'NAME := EXPR'?" bothers me a bit, but it's the implementation
> implications of parent local scoping that I fear will create a
> semantic tar pit we can't get out of later.
>
>> but -1 for (b). IIRC (b) originated with
>> Tim. But his essay on the topic, included as Appendix A
>> (https://www.python.org/dev/peps/pep-0572/#appendix-a-tim-peters-s-findings)
>> does not even mention comprehensions. However, he did post his motivation
>> for (b) on python-ideas, IIRC a bit before PyCon; and the main text of the
>> PEP gives a strong motivation
>> (https://www.python.org/dev/peps/pep-0572/#scope-of-the-target).
>> Nevertheless, maybe we should compromise and drop (b)?
> Unfortunately, I think the key rationale for (b) is that if you
> *don't* do something along those lines, then there's a different
> strange scoping discrepancy that arises between the non-comprehension
> forms of container displays and the comprehension forms:
>
>      (NAME := EXPR,) # Binds a local
>      tuple(NAME := EXPR for __ in range(1)) # Doesn't bind a local
>
>      [NAME := EXPR] # Binds a local
>      [NAME := EXPR for __ in range(1)] # Doesn't bind a local
>      list(NAME := EXPR for __ in range(1)) # Doesn't bind a local
>
>      {NAME := EXPR} # Binds a local
>      {NAME := EXPR for __ in range(1)} # Doesn't bind a local
>      set(NAME := EXPR for __ in range(1)) # Doesn't bind a local
>
>      {NAME := EXPR : EXPR2} # Binds a local
>      {NAME := EXPR : EXPR2 for __ in range(1)} # Doesn't bind a local
>      set((NAME := EXPR, EXPR2) for __ in range(1)) # Doesn't bind a local
>
> Those scoping inconsistencies aren't *new*, but provoking them
> currently involves either class scopes, or messing about with
> locals().

I've got an idea about this.

The fact is, assignments don't make much sense in an arbitrary part of a 
comprehension:
`for' variables are assigned every iteration, so when the result is 
returned, only the final value will be seen.
(And if you need a value every iteration, just go the explicit way and 
add it to the returned tuple.)

Contrary to that, the "feeder" expression is only evaluated once at the 
start -- there, assignments do make sense.
Effectively, it's equivalent to an additional line:

seq = range(calculate_b() as bottom, calculate_t() as top)
results = [calculate_r(bottom,r,top) for r in seq]

So, I suggest to evaluate the "feeder" expression in a local scope but 
expressions that are evaluated every iteration in a private scope.

-- 
Regards,
Ivan