Lambda forms and scoping

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Sun Mar 22 22:26:23 EDT 2009


En Sun, 22 Mar 2009 16:42:21 -0300, R. David Murray  
<rdmurray at bitdance.com> escribió:
> "Gabriel Genellina" <gagsl-py2 at yahoo.com.ar> wrote:

>> And if you imply that *where* you call a function does matter, it does
>> not. A function carries its own local namespace, its own closure, and  
>> its
>> global namespace. At call time, no additional "binding" is done (except
>> parameters -> arguments).
>
> I poked around in the API docs and experimented with func_closure and
> related attributes, and after bending my brain for a while I think I
> understand this.  The actual implementation of the closure is a single
> list of 'cell' objects which represent namespace slots in the nested
> scopes in which the closed-over function is defined.
>
> But the fact that it is a single list is an implementation detail, and
> the implementation is in fact carefully designed so that conceptually
> we can think of the closure as giving the function access to those
> nested-scope namespaces in almost(*) the same sense that it has a
> reference to the global and local namespaces.  That is, if what a name
> in _any_ of those namespaces points to is changed, then the closed-over
> function sees those changes.
>
> In this way, we understand the original example:  when defining a
> lambda having a 'free variable' (that is, one not defined in either the
> local or global scope) that was a name in the surrounding function's
> local namespace, the lambda is going to see any changes made by the
> surrounding function with regards to what that name points to.  Thus,
> the final value that the lambda uses is whatever the final value of the
> for loop variable was when the surrounding function finished executing.

Exactly.

> However, I think that a Python closure is not quite the same thing as a
> 'computer science' closure, for the same reason that people coming from a
> language with variables-and-values as opposed to namespaces get confused
> when dealing with Python function call semantics.  Consider:
>
>     http://en.wikipedia.org/wiki/Closure_(computer_science)
>
> That says that a closure can be used to provide a function with a private
> set of variables that persist from one invocation to the next, so that
> a value established in one call can be accessed in the next.  The last
> part of that sentence is not true in Python, since any assignment inside
> a function affects only the local (per-invocation) namespace or (given
> a global statement) the global namespace.  A function cannot change the
> thing pointed to by a name in the closure.  Only the outer function,
> for whom that name is in its local namespace, can do that.

That's true in Python 2.x, but 3.x has the "nonlocal" keyword - so you can  
modify variables in outer scopes too:

p3> z = 1
p3> def o():
...   z = 2
...   def i():
...     nonlocal z
...     print("z in i:", z)
...     z = 5
...   print("z in o:", z)
...   i()
...   print("z in o:", z)
...   z=3
...   print("z in o at exit:", z)
...   return i
...
p3> i=o()
z in o: 2
z in i: 2
z in o: 5
z in o at exit: 3
p3> z
1
p3> i()
z in i: 3
p3> i()
z in i: 5

(Anyway I think the inability to "modify" a variable doesn't invalidate  
the "closure" concept...)

-- 
Gabriel Genellina




More information about the Python-list mailing list