Working with Captured Variables in Python Closures

Saturday April 25, 2015

You can make closures in Python like this:

def add_some(x=0):
    def adder(y):
        return x+y
    return adder

add3 = add_some(3)

print(add3(7))
## 10

The adder function "remembers" x.

But this will fail:

def a_counter(count=0):
    def counter():
        count += 1
        return count
    return counter

the_counter = a_counter()

print(the_counter())
## UnboundLocalError: local variable 'count' referenced before assignment

You can't assign to count in there!

In Python 3, you can resolve this with nonlocal:

def a_counter(count=0):
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

the_counter = a_counter()

print(the_counter())
## 1

print(the_counter())
## 2

print(the_counter())
## 3

Great! I'd rather not have to specify nonlocal, but I'm happy to know of another feature unique to Python 3.

In Python 2, you can't get assignment of captured variables inside your closure, but you can mutate a captured variable. ¯\_(ツ)_/¯

def a_counter(count={'val': 0}):
    def counter():
        count['val'] += 1
        return count['val']
    return counter

the_counter = a_counter()

print(the_counter())
## 1

print(the_counter())
## 2

print(the_counter())
## 3

Hooray for closures!