On 28 February 2018 at 08:27, Chris Angelico <rosuav@gmail.com> wrote:
This is a suggestion that comes up periodically here or on python-dev.
This proposal introduces a way to bind a temporary name to the value
of an expression, which can then be used elsewhere in the current
statement.

The nicely-rendered version will be visible here shortly:

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

Thanks for putting this together!

 
Statement-local name bindings can be used in any context, but should be
avoided where regular assignment can be used, just as `lambda` should be
avoided when `def` is an option.

 
[snip]
 

2. The current implementation [1] implements statement-local names using
   a special (and mostly-invisible) name mangling.  This works perfectly
   inside functions (including list comprehensions), but not at top
   level.  Is this a serious limitation?  Is it confusing?

It isn't clear to me from the current PEP what the intended lifecycle of the bound names actually is, especially for compound statements.

Using list comprehensions as your example currently hides that confusion, since they create an implicit nested scope anyway, so the references will go away when the list comprehension terminates no matter what.

So I think it would be useful to have some other examples in the PEP to more explicitly answer that question:

    x = (expr as y)
    assert x == y # Does this pass? Or raise NameError for 'y'?

    if (condition as c):
        assert c # Does this pass? Or raise NameError for 'c'?
    else:
        assert not c # Does this pass? Or raise NameError for 'c'?
    assert c or not c # Does this pass? Or raise NameError for 'c'?

    class C:
        x = (True as y)
    assert C.y # Does this pass? Or raise AttributeError for 'y'?

I think it would also be worth explicitly considering a syntactic variant that requires statement local references to be explicitly disambiguated from regular variable names by way of a leading dot:

    result = [[(f(x) as .y), .y] for x in range(5)]

    (.x, (1 as .x), .x) # UnboundLocalError on first subexpression
    (x, (1 as .x), .x) # Valid if 'x' is a visible name

    x = (expr as .y)
    assert x == .y # UnboundLocalError for '.y'

    if (condition as .c):
        assert .c # Passes
    else:
        assert not .c # Passes
    assert .c or not .c # UnboundLocalError for '.c'

    class C:
        x = (True as .y)
    assert C..y # SyntaxError on the second dot

Since ".NAME" is illegal for both variable and attribute names, this makes the fact statement locals are a distinct namespace visible to readers as well as to the compiler, and also reduces the syntactic ambiguity in with statements and exception handlers.

Cheers,
Nick.

--
Nick Coghlan   |   ncoghlan@gmail.com   |   Brisbane, Australia