- Published on
Closures in Python
Closures are one of those Python features that sound scary until you see them—and then they click 😄 Let’s walk through it gently.
The idea in plain English
A closure is a function that:
- is defined inside another function
- remembers variables from the outer function even after the outer function has finished running
So the inner function “closes over” those variables. Hence the name closure.
A tiny example
def outer():
x = 10
def inner():
print(x)
return inner
Now watch this:
f = outer() # outer() finishes execution
f() # prints 10
Even though outer() is done, inner() still remembers x = 10.
👉 That’s a closure.
Why is this interesting?
Because normally, local variables disappear when a function returns. Closures keep them alive.
Another example (more practical)
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier
Use it like this:
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
What’s happening:
nis local tomake_multiplier- each returned
multiplierfunction remembers its ownn doubleremembersn = 2tripleremembersn = 3
Each returned function has its own closure state.
Key properties of closures
A function is a closure if:
- It is nested (defined inside another function)
- It references variables from the outer function
- The outer function has already returned
Inspecting a closure (optional nerd bit 🤓)
print(double.__closure__)
You’ll see something like:
(<cell at 0x...: int object at ...>,)
That “cell” is where Python stores the remembered value (n = 2).
Modifying outer variables: nonlocal
If you want to change a captured variable:
def counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc
c = counter()
c() # 1
c() # 2
c() # 3
Without nonlocal, Python would think count is a new local variable.
When are closures actually useful?
Closures are great for:
- Function factories (like
make_multiplier) - Configuration without globals
- Callbacks
- Decorators (closures are the backbone of decorators)
- Keeping state without using classes
Closures vs classes (intuition)
This:
def make_adder(n):
return lambda x: x + n
Is conceptually similar to:
class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return x + self.n
Closures = lightweight objects with hidden state.