[Python-ideas] A "local" pseudo-function
Tim Peters
tim.peters at gmail.com
Tue May 1 13:08:43 EDT 2018
[Tim]
> ...
> Here's an example where I don't know what the consequences of "the
> rules" should be:
>
> def f():
> a = 10
> local a:
> def showa():
> print("a is", a)
> showa() # 10
> a = 20
> showa() # 20
> a = 30
> showa() # 10
>
> The comments show what the output would be under the "nothing about
> scope rules change" meaning. They're all obvious (since there is is
> no new scope then - it's all function-local).
>
> But under the other meaning ...?
>
> The twist here is that `def` is an executable statement in Python, and
> is a "binding site" for the name of the function being defined. So
> despite that `showa` appears to be defined in a new nested lexical
> scope, it's _actually_ bound as a function-local name. That's bound
> to be surprising to people from other languages: "I defined it in a
> nested lexical scope, but the name is still visible after that scope
> ends?".
>
> I don't know what the first `showa()` is intended to do. Presumably
> `a` is unbound at the start of the new nested scope? So raises
> NameError? If so, comment that line out so we can make progress ;-)
>
> It seems clear that the second `showa()` will display 20 under any reading.
>
> But the third? Now we're out of the `local a:` scope, but call a
> function whose textual definition was inside that scope. What does
> `showa()` do now to find a's value? f's local `a` had nothing to do
> with the `a` in the nested scope, so presumably it shouldn't display
> 10 now. What should it do?
> Does the final state of the nested scope's locals need to preserved so
> that showa() can display 30 instead? Or ...?
Just noting that a sane way to answer such questions is to model the
intent with nested functions in current Python. It's annoying because
you have to explicitly declare the _non_-local names instead, and also
make dummy assignments to those names to tell Python in which scope
they _should_ be bound.
So, e.g., for the above you can write this:
def f():
a = 10
# Have to give `showa` _some_ binding in its intended scope,
# else the "nonlocal showa" below is a compile-time error
showa = None
def local_a():
nonlocal showa
def showa():
print("a", a)
#showa() # raises NameError
a = 20
showa() # 20
a = 30
local_a()
del local_a
showa() # 30
print("but f's a is", a) # 10
The comments show what happens when you call `f()`, matching the
guesses in the original message.
One thing to note: if this does model the intent, it's essentially
proof that it's implementable without intractable effort; e.g., the
machinery needed to implement funky closures already exists.
But another: since I've never seen code anything like this before,
that casts doubt on whether the semantics are actually useful in real
life.
That's why I always ask for real use cases ;-)
More information about the Python-ideas
mailing list