G
geremy condra
The availability of "nonlocal" binding semantics also makes the
semantics much easier to define than they were in those previous
discussions (the lack of clear semantics for name binding statements
with an attached local namespace was the major factor blocking
creation of a reference implementation for this proposal back then).
For example:
c = sqrt(a*a + b*b) where:
a = retrieve_a()
b = retrieve_b()
could translate to something like:
def _anon(): # *(see below)
nonlocal c
a = retrieve_a()
b = retrieve_b()
c = sqrt(a*a + b*b)
_anon()
*(unlike Python code, the compiler can make truly anonymous functions
by storing them solely on the VM stack. It already does this when
executing class definitions):
I like this idea, but I would tweak it slightly. Maybe we should say
EXPRESSION where:
BLOCK
is equivalent to
def _():
BLOCK
return EXPRESSION
_()
That way, c = a where: a = 7 would be equivalent to
def _():
a = 7
return a
c = _()
One advantage of this equivalence is it would make it easier to work
around a longstanding scoping gotcha. A naïve coder might expect this
code to print out numbers 0 to 4:
>>> fs = []
>>> for n in range(5):
... def f():
... print(item)
... fs.append(f)
...
>>> [f() for f in fs]
4
4
4
4
4
[None, None, None, None, None]
I think we all have enough experience to know this isn’t a totally
unrealistic scenario. I personally stumbled into when I was trying to
create a class by looping through a set of method names.
To get around it, one could use a where clause like so:
fs = []
for n in range(5):
fs.append(f) where:
shadow = n
def f():
print(shadow)
This would print out 0 to 4 as expected and be equivalent to
>>> fs = []
>>> for n in range(5):
... def _():
... shadow = n
... def f():
... print(shadow)
... fs.append(f)
... _()
...
>>> [f() for f in fs]
0
1
2
3
4
[None, None, None, None, None]
I think a where-clause with def-like namespace semantics would be a
positive addition to Python, once the moratorium is up.
-- Carl Johnson
+1 from me, FWIW
Geremy Condra