⬅ Previous Topic
Python GeneratorsNext Topic ⮕
Python Decorators⬅ Previous Topic
Python GeneratorsNext Topic ⮕
Python DecoratorsIn Python, closures are a powerful and often misunderstood concept. If you've ever wondered how a function can remember the environment in which it was created—even after that environment is gone—then you're ready to dive into closures.
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.
Closures allow you to:
Let’s break it down with an example. The closure is formed when three conditions are met:
def outer_function(msg):
def inner_function():
print(f"Message: {msg}")
return inner_function
# Create the closure
my_closure = outer_function("Hello Closure!")
# Now call the closure
my_closure()
Message: Hello Closure!
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
.
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.
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.
nonlocal
to modify enclosed variables. Without it, Python treats them as read-only.def no_closure():
x = 5
def show():
print("Hello")
return show
fn = no_closure()
print(fn.__closure__) # Will print None
None
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
Closures are useful when:
Closures are not just a technical trick—they allow for cleaner, more modular, and more reusable code. By remembering the context in which they were created, closures enable inner functions to maintain state across multiple invocations, even after their outer function is long gone.
Now that you understand closures, try writing one that returns a custom logger or message formatter. Experiment with modifying state, returning different outputs, or wrapping other functions!
⬅ Previous Topic
Python GeneratorsNext Topic ⮕
Python DecoratorsYou can support this website with a contribution of your choice.
When making a contribution, mention your name, and programguru.org in the message. Your name shall be displayed in the sponsors list.