Python · The language, not just syntax

How do closures work in Python?

MediumclosuresscopenonlocalUpdated Oct 2026
Quiz this track

Short answer

A closure is a nested function that captures variables from an enclosing scope and keeps them alive after the outer function returns. Reading is automatic; rebinding requires nonlocal.

Python resolves names lexically. A nested function that references a variable from its enclosing function stores it in a cell, and the function object keeps that cell. The captured variable is shared, not copied, so all closures over the same cell see the latest value.

python
def counter():
    count = 0

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

    return increment

next_id = counter()
print(next_id(), next_id())

functions = [lambda: i for i in range(3)]
print([fn() for fn in functions])
Without nonlocal, count += 1 would raise UnboundLocalError. The lambda list prints the final value of i three times.

Where closures show up

  • Decorators that wrap a function and keep a reference to it
  • Factory functions that preconfigure behaviour
  • Callbacks that need state across invocations
  • The late-binding trap in loops, fixed with a default argument

Late binding catches people because the closure looks up the variable when it runs, not when it is defined. Bind the current value with lambda i=i: i, or use functools.partial, or restructure the loop into a function call.

Closures retain references, so capturing a large object keeps it alive. That is a subtle source of memory growth in long-lived callbacks and caches.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1Why does a list of lambdas in a loop all return the same value?
  2. 2What does nonlocal change?
  3. 3How can a closure cause a memory leak?
  4. 4How is a closure different from a class with state?

Say it in the interview

A closure is a nested function that keeps references to variables in its enclosing scope, even after that scope returns. Reads are automatic, but rebinding needs nonlocal. The classic bug is late binding in loops, where every lambda reads the final value of the loop variable, so I bind it with a default argument or use partial. I also watch for captured objects keeping memory alive in long-lived callbacks.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Python mock interview and get scored feedback on depth, clarity and confidence.