scoping weirdness
Eyal Lotem
eyal at hyperroll.com
Sat Aug 25 15:08:41 EDT 2001
Paul Rubin wrote:
> from __future__ import nested_scopes # python 2.1.1
>
> def foo (n):
> a = lambda: 'you said (%d)' % n
> n += 3
> return a
>
> x = foo(1)
> print x()
>
> This prints 4, rather than 1 as I would have expected.
> I think I understand what's going on, but is it really what was intended?
> Is there a preferred way of writing this kind of function?
>
> Thanks.
There are two issues:
A) What does the nested scope 'n' refer to: the object that 'n' evaluates
at the external scope at the time of the lambda definition, or is it the
same 'n' reference as in the external scope.
B) Is the function's scope 'n' reference the same reference as the given
parameter.
I think the answer to question B is obvious since far before nested scopes
were introduced:
def f(n):
n = n + 1
a = 1
f(a)
was never expected to increase a, thus: the function's scope 'n' reference
is NOT the same reference as the given parameter.
The answer to A is that the internal-scope reference 'n' IS the same
reference as the external scope 'n', and reassigning the 'n' reference in
the external scope means that the internal-scope 'n' reference is changed.
Another possible behaviour would be to 'emulate' argument-type behaviour in
nested scopes, so that when defining the lambda, the named references seem
to be given by argument, and assigned to refer to the same objects as the
external scope. This is utterly bogus, and would require all the symbol
names in the nested scope to exist in the external scope at the time of
definition of the lambda, which stands in contrast to the dynamic approach
of delaying the binding to the last possible time.
These two answers explain the result of the code you have.
The reference to the '1' object given to the function 'foo' is distinct
from the reference 'n'. The reference 'n' is set to refer to the object
'4' in function 'foo'. The internal-function reference 'n' IS the
internal-lambda reference 'n', which means that when reassigning 'n' to 4
the internal-lambda reference is also refering to 4, which explains the
resulted behaviour.
I think this behaviour is the only way to go, otherwise we're contradicting
A or B which would contrast strong Python ideas.
Note that this is all based on my understanding of nested scopes and their
implementation, which is limited to a very small experience with them.
However, I do feel I have an understanding of the issue.
More information about the Python-list
mailing list