Converting functions

Peter Otten __peter__ at web.de
Mon Jan 24 06:55:07 EST 2011


Edmunds Cers wrote:

> Peter Otten <__peter__ at web.de> writes:
> 
>> I don't know how to express it more clearly, so here's another example:
>>
>>>>> def f():
>> ...     def g(): return a * a
>> ...     def h(): return a + a
>> ...     a = 5
>> ...     return g, h
>> ...
>>>>> g, h = f()
>>>>> g(), h()
>> (25, 10)
> 
> IMHO this whole confusion just shows that mingling assignment and
> binding makes understanding scope harder. In Python, the first
> assignment inside a function body also creates a binding (unless told
> not to do so by global) the scope of which is the _whole_ of the
> function body. A variable reference refers to the lexically innermost
> surrounding binding of said variable. Now, while it might seem that some
> magic happens in the example on the return of the function, this is in
> fact not so, since the assignment "a = 5" actually creates a binding for
> /a/ that is visible from the body of /g/, because the lexical scope of
> the binding is the whole body of /f/, so that the capture of the
> variable happens inside of the def expression (as one would expect) and
> not on return as you seem to imply.
> 
> Slightly OT -- the above also explains why closed over variables are
> read only in Python. An assignment inside a closure would implicitly
> create a binding, so that all (even previous) references to that
> variable would refer to this new binding.

Well, in Python 3 they no longer are, courtesy of the nonlocal statement:

>>> def f():
...     def set(x):
...             nonlocal a
...             a = x
...     def get():
...             return a
...     return get, set
...     a = 42
...
>>> get, set = f()
>>> get()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in get
NameError: free variable 'a' referenced before assignment in enclosing scope
>>> set(42)
>>> get()
42

That closed-over variables are read-only by default is just to avoid the 
ambiguity about the scope they are supposed to live in, just like global 
variables that are to be changed from within a function.

Peter



More information about the Python-list mailing list