[Python-ideas] A "local" pseudo-function

Tim Peters tim.peters at gmail.com
Tue May 1 13:08:43 EDT 2018

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

That's why I always ask for real use cases ;-)

More information about the Python-ideas mailing list