Edmunds Cers wrote: > Peter Otten <__pete...@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 -- http://mail.python.org/mailman/listinfo/python-list