Python Closures Explained: How Nested Functions Capture Variables
Python Closures
Discover how Python closures work, how to define them, and why they’re essential for clean, efficient code.
Nonlocal Variables in a Nested Function
Before exploring closures, it’s crucial to understand nested functions and nonlocal variables. A function defined inside another function is called a nested function. Such functions can read variables from their enclosing scope.
In Python, these non‑local variables are read‑only by default. To modify them, you must explicitly declare the variable as nonlocal within the nested function.
Below is a simple example showing a nested function accessing a non‑local variable.
def print_msg(msg):
# Outer function
def printer():
# Nested function
print(msg)
printer()
# Execute
print_msg("Hello")
Output
Hello
The nested printer() function can access the msg variable from its outer scope.
Defining a Closure Function
What if the outer function returned the nested function instead of calling it? The code would look like this:
def print_msg(msg):
def printer():
print(msg)
return printer # Return the nested function
# Store the returned function
another = print_msg("Hello")
another()
Output
Hello
Notice that the function printer still remembers the value of msg even after print_msg has finished executing. This phenomenon—where a function retains access to variables from its defining scope—is called a closure in Python.
To illustrate further, delete the original function and see that the returned function still works:
>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined
The returned function continues to function because it captured the necessary data in its closure.
When Do We Have Closures?
In Python, a closure exists when a nested function:
- is defined inside another function.
- references a variable from its enclosing function.
- is returned by the outer function.
When to Use Closures?
Closures offer several advantages:
- They eliminate the need for global variables, enhancing encapsulation.
- They provide a lightweight alternative to single‑method classes, keeping code concise.
- They enable functional patterns such as decorators, where a wrapper function needs access to the original function’s arguments.
Below is a common example: a factory that creates multiplier functions.
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# Create specific multipliers
times3 = make_multiplier_of(3)
times5 = make_multiplier_of(5)
print(times3(9)) # 27
print(times5(3)) # 15
print(times5(times3(2))) # 30
Output
27 15 30
Python’s decorator syntax relies heavily on closures. When you write a decorator, the wrapper function captures the function it decorates, forming a closure.
To inspect a closure, use the __closure__ attribute. It returns a tuple of cell objects that hold the enclosed values. For example:
>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
Each cell’s cell_contents attribute holds the actual value captured by the closure:
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5
Understanding closures empowers you to write cleaner, more modular Python code that avoids unnecessary globals and embraces functional paradigms.
Python
- Master Python Functions: Syntax, Types, and Practical Examples
- Mastering Python Function Arguments: Positional, Keyword, and Default Parameters
- Mastering Python Recursion: How Functions Call Themselves
- Python Lambda Functions: A Practical Guide to Anonymous Functions
- Python Generators: Efficient Iteration and Advanced Use Cases
- Mastering Python Decorators: Enhance Functions with Expert Techniques
- Mastering Python’s strip() Method: Comprehensive Guide & Practical Examples
- Python round() Function Explained with Practical Examples
- Mastering Python's map() Function: Syntax, Examples, and Best Practices
- Python Functions Explained: Building Reusable Code Modules