Python Closures

By

Learn how closures work in Python: when you return a nested function, it keeps access to the variables of its enclosing function even after it ends.

~~~

A closure is a function that remembers the variables of the function it was defined in, even after that outer function has finished running.

We’ve previously seen how to create a nested function in Python.

If you return a nested function from a function, that nested function has access to the variables defined in that function, even if that function is not active any more.

This lets you keep state around without using a class or a global variable.

Here is a simple counter example.

def counter():
    count = 0

    def increment():
        nonlocal count
        count = count + 1
        return count

    return increment

increment = counter()

print(increment()) # 1
print(increment()) # 2
print(increment()) # 3

We return the increment() inner function, and that has still access to the state of the count variable even though the counter() function has ended.

Nothing outside the closure can read or change count. The variable is private to the functions created by counter().

Why do we need nonlocal?

Reading an outer variable from a nested function works out of the box. Assigning to it does not.

When you assign to a variable inside a function, Python treats it as a local variable of that function. Without nonlocal, the line count = count + 1 tries to read a local count that doesn’t exist yet, and you get an error:

UnboundLocalError: cannot access local variable 'count'
where it is not associated with a value

That’s the most common pitfall with closures. If you only read the variable, you don’t need nonlocal. As soon as you assign to it, you do.

The nonlocal declaration tells Python “this name belongs to the enclosing function, don’t create a new local one”.

Each call creates a new closure

Every time you call counter(), you get a fresh, independent counter:

first = counter()
second = counter()

print(first())  # 1
print(first())  # 2
print(second()) # 1

first and second each hold their own count variable. They don’t share state.

This is what makes closures useful in practice. You can create many small functions, each carrying its own private data, from a single factory function.

Tagged: Python · All topics
~~~

Related posts about python: