









Python Closures
What is a Closure in Python?
A closure is a nested function that captures the state of its enclosing scope—even if that scope has finished execution. This allows the inner function to remember variables from the outer function.
Why Do Closures Matter?
Closures allow you to:
- Preserve data across function calls without using global variables
- Write more concise and elegant code
- Implement decorators and function factories
How to Create a Closure
Let’s break it down with an example. The closure is formed when three conditions are met:
- There is a nested function
- The nested function references variables from the outer function
- The outer function returns the nested function
def outer_function(msg):
def inner_function():
print(f"Message: {msg}")
return inner_function
# Create the closure
my_closure = outer_function("Hello World!")
# Now call the closure
my_closure()
Message: Hello World!
What Just Happened?
Even though outer_function
has already finished executing, the variable msg
still exists in memory. That's because inner_function
has "closed over" the variable msg
.
Checking for Closure
We can actually inspect the closure using the __closure__
attribute.
print(my_closure.__closure__)
print(my_closure.__closure__[0].cell_contents)
(<cell at 0x...: str object at 0x...>,)
Hello Closure!
This confirms that msg
is stored as part of the closure environment.
Real-World Use Case: Counter Generator
Closures shine when used to create functions that remember state. Here’s a classic counter example:
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
# Create a counter function
counter1 = make_counter()
print(counter1())
print(counter1())
print(counter1())
1
2
3
The variable count
is preserved between function calls thanks to the closure.
Common Pitfalls and Checks
- Don’t expect the outer function's variables to persist unless they are referenced in the inner function.
- Use
nonlocal
to modify enclosed variables. Without it, Python treats them as read-only. - A closure is not created if the inner function doesn’t reference outer variables.
def no_closure():
x = 5
def show():
print("Hello")
return show
fn = no_closure()
print(fn.__closure__) # Will print None
None
In this example, the inner function show() does not reference any of the outer variables. Therefore, a closure is not created.
Closures vs. Lambda Functions
Closures can also be created using lambda expressions, which is common in factory functions or decorators.
def multiplier(factor):
return lambda x: x * factor
double = multiplier(2)
print(double(5)) # 10
10
Recap: When to Use Closures
Closures are useful when:
- You want to keep some data private (function-level encapsulation)
- You need a factory function that generates other functions with customized behavior
- You’re building decorators or callback systems