Scoping Issues

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu May 24 21:50:15 EDT 2012


On Thu, 24 May 2012 18:23:18 -0700, SherjilOzair wrote:

> def adder():
> 	s = 0
> 	def a(x):
> 	    s += x
> 	    return sum
> 	return a

I think you mean "return s", not sum.


> This should work, right? Why does it not?

No, it shouldn't. When you have an assignment, such as "s += x", Python 
treats s as a local variable. Since s is local to the inner function a(), 
it has no initial value, and the += fails.

In Python 3, you can declare s to be a non-local variable with the 
nonlocal keyword:

def adder():
    s = 0
    def a(x):
        nonlocal s
        s += x
        return s
    return a


which now works the way you should expect:

>>> add = adder()
>>> add(1)
1
>>> add(2)
3
>>> add(5)
8


But in Python 2, which you are using, there is no nonlocal keyword and 
you can only write to globals (declaring them with the global keyword) or 
locals (with no declaration), not nonlocals.

There are a number of work-arounds to this. One is to use a callable 
class:

class Adder:
    def __init__(self):
        self.s = 0
    def __call__(self, x):
        self.s += x
        return self.s


Another is to use an extra level of indirection, and a mutable argument. 
Instead of rebinding the non-local, you simply modify it in place:

def adder():
    s = [0]
    def a(x):
        s[0] += x
        return s[0]
    return a



-- 
Steven



More information about the Python-list mailing list