← Back to Python Course | Chapter 4: Functions | Lesson 9 of 9

Python Closures

A closure is a function that remembers the values from where it was created, like a backpack that keeps its things even after you leave home. It can use them later.
Syntax
python
def outer(outer_variable):
    def inner():
        return outer_variable
    return inner

closure = outer(value)

What is a Closure?

A closure is a function that "remembers" the variables from the scope it was defined in, even after that outer function has already finished running and would otherwise have discarded them.

Example: What is a Closure?

python
def outer():
    message = "Hi"
    def inner():
        print(message)  # inner "remembers" message even after outer returns
    return inner

closure = outer()
closure()  # message is still accessible here

Preserving Outer State

Because a closure locks in specific values from its enclosing scope, you can use one to generate specialized helper functions on demand — like a make_multiplier(3) that returns a function which always multiplies by 3, without hardcoding that 3 everywhere it's needed.

Example: Preserving Outer State

python
def make_multiplier(factor):
    def multiplier(x):
        return x * factor  # factor is captured from the enclosing call
    return multiplier

times3 = make_multiplier(3)  # locks in factor=3
print(times3(10))

Inspecting Closures

Every closure exposes a __closure__ attribute containing "cell" objects that hold references to the exact variables it captured, which is how Python keeps those values alive after the enclosing function has otherwise returned.

Example: Inspecting Closures

python
def make_multiplier(factor):
    def multiplier(x):
        return x * factor
    return multiplier

times3 = make_multiplier(3)
print(times3.__closure__[0].cell_contents)  # inspects the captured factor value directly

Dynamic State Modifications

The nonlocal keyword lets a closure not just read but actually modify a captured variable from its enclosing scope, which is how you can build a simple counter or accumulator using only nested functions instead of a class.

Example: Dynamic State Modifications

python
def make_counter():
    count = 0
    def counter():
        nonlocal count  # allows modifying the captured count variable
        count += 1
        return count
    return counter

counter = make_counter()
print(counter())  # 1
print(counter())  # 2, count persists between calls

When to Use Closures

Closures are a lightweight alternative to defining a whole class when you only need to bundle one small piece of behavior with some remembered state — reach for a class instead once you need multiple related methods sharing that state.

Example: When to Use Closures

python
def make_counter():  # closure: one small behavior + state
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

# A class would be overkill here for just one counter method
c = make_counter()
print(c(), c())
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Expecting a closure to capture a loop variable's value at creation time, so [lambda: i for i in range(3)] all return 2 because they share one i.
  2. Assigning to an outer variable inside the inner function without nonlocal, which makes Python treat it as a new local and raise UnboundLocalError.
  3. Calling the outer function without calling the result, as in counter = make_counter instead of make_counter(), so you get the function itself and not the inner closure.
Chapter Summary
  • Functions group reusable code, take parameters, and return values, with default arguments, *args, and **kwargs adding flexibility.
  • Recursion, lambda functions, scope, and closures describe more advanced function behavior.
  • Understanding scope and lifetime shows where variables can be used.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.