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

Steven D'Aprano steve at pearwood.info
Mon Apr 30 12:20:28 EDT 2018


On Sun, Apr 29, 2018 at 01:36:31PM +1000, Chris Angelico wrote:

[...]
> > While I started off with Python 1.5, I wasn't part of the discussions
> > about nested scopes. But I'm astonished that you say that nested scopes
> > were controversial. *Closures* I would completely believe, but mere
> > lexical scoping? Astonishing.
> 
> I'm not sure how you can distinguish them:

Easily. Pascal, for example, had lexical scoping back in the 1970s, but 
no closures. I expect Algol probably did also, even earlier. So they are 
certainly distinct concepts.

(And yes, Pascal functions were *not* first class values.)


> What you expect here is lexical scope, yes. But if you have lexical 
> scope with no closures, the inner function can ONLY be used while its 
> calling function is still running. What would happen if you returned 
> 'inner' uncalled, and then called the result? How would it resolve the 
> name 'x'?

Failing to resolve 'x' is an option. It would simply raise NameError, 
the same as any other name lookup that doesn't find the name.

Without closures, we could say that names are looked up in the following 
scopes:

# inner function, called from inside the creating function
(1) Local to inner.
(2) Local to outer (nonlocal).
(3) Global (module).
(4) Builtins.


If you returned the inner function and called it from the outside of the 
factory function which created it, we could use the exact same name 
resolution order, except that (2) the nonlocals would be either absent 
or empty.

Obviously that would limit the usefulness of factory functions, but 
since Python 1.5 didn't have closures anyway, that would have been no 
worse that what we had.

Whether you have a strict Local-Global-Builtins scoping, or lexical 
scoping without closures, the effect *outside* of the factory function 
is the same. But at least with the lexical scoping option, inner 
functions can call each other while still *inside* the factory.

(Another alternative would be dynamic scoping, where nonlocals becomes 
the environment of the caller.)


> I can't even begin to imagine what lexical scope would do in
> the absence of closures. At least, not with first-class functions.

What they would likely do is raise NameError, of course :-)

An inner function that didn't rely on its surrounding nonlocal scope 
wouldn't be affected. Or if you had globals that happened to match the 
names it was relying on, the function could still work. (Whether it 
would work as you expected is another question.)

I expect that given the lack of closures, the best approach is to simply 
make sure that any attempt to refer to a nonlocal from the surrounding 
function outside of that function would raise NameError.

All in all, closures are much better :-)



-- 
Steve


More information about the Python-ideas mailing list