On 1 March 2018 at 06:34, Chris Angelico firstname.lastname@example.org wrote:
On Thu, Mar 1, 2018 at 7:28 AM, Paul Moore email@example.com wrote:
I've no idea how that would work under statement-local names either,
boom = lambda: boom() boom()
is just an infinite recursion. I'm less sure that the as version is. Or the alternative form
((lambda: boom()) as boom)()
I know you can tell me what the implementation does - but I can't reason it out from the spec.
The only part that isn't yet properly specified is how this interacts with closures, and that's because I really don't know what makes sense. Honestly, *any* situation where you're closing over a SLNB is going to have readability penalties, no matter what the spec says.
My suggestion is to just flat out prohibit it - if closures can capture the reference, then it isn't a statement local name binding any more, and it's reasonable to ask folks to promote it to a regular function local variable.
This is another area where syntactic disambiguation on the reference side would help
# prints 12 twice x = 12 if (1 as .x) == 1: def foo(): return x print(foo()) print(foo())
# prints 1 twice x = 12 if (1 as .x) == 1: x = .x def foo(): return x print(foo()) print(foo())
# Raises UnboundLocalError x = 12 if (1 as .x) == 1: def foo(): return .x print(foo()) print(foo())
That last example could potentially even raise a compile time error during the symbol table analysis pass, since the compiler would *know* there's no statement local by that name in the current lexical scope, and statement local references wouldn't have a runtime fallback to module globals or the builtins the way regular variable references do.
Another perk of using the ".NAME" syntax is that we could extend it to allow statement local name bindings in for loops as well:
for .i in range(10): print(.i) # This is fine print(.i) # This is an error (unless an outer statement also sets .i)