Why can’t Python increment variable in closure?

You can’t re-bind closure variables in Python 2. In Python 3, which you appear to be using due to your print(), you can declare them nonlocal:

def foo():

  counter = 1

  def bar():
    nonlocal counter
    counter += 1
    print("bar", counter)

  return bar

bar = foo()
bar()

Otherwise, the assignment within bar() makes the variable local, and since you haven’t assigned a value to the variable in the local scope, trying to access it is an error.

In Python 2, my favorite workaround looks like this:

def foo():

  class nonlocal:
    counter = 1

  def bar():
    nonlocal.counter += 1
    print("bar", nonlocal.counter)

  return bar

bar = foo()
bar()

This works because mutating a mutable object doesn’t require changing what the variable name points to. In this case, nonlocal is the closure variable and it is never reassigned; only its contents are changed. Other workarounds use lists or dictionaries.

Or you could use a class for the whole thing, as @naomik suggests in a comment. Define __call__() to make the instance callable.

class Foo(object):

    def __init__(self, counter=1):
       self.counter = counter

    def __call__(self):
       self.counter += 1
       print("bar", self.counter)

bar = Foo()
bar()

Leave a Comment