Python is an object-oriented programming language that supports functional programming. In functional programming, functions are treated as first-class objects. This means that functions can be assigned to variables, passed as arguments to other functions, and returned as values from functions. One of the powerful concepts in functional programming is the use of closures. In this blog post, we will explore what closures are, how they work, and how to use them in Python programming.
Before learning about closures in python make sure you have a good knowledge of Python Inner Function or Nested Function, as those examples will be extended in this topic.
Let’s learn about Closures in Python.
What are Closures in Python?
A closure is a function object that has access to variables in its enclosing lexical scope, even when the function is called outside that scope. A closure can “remember” the values of the variables in the enclosing scope, and use them each time it is called. The concept of closures is based on the concept of lexical scoping.
To understand closures, let’s look at an example. Consider the following code snippet:
def outer_func(x):
def inner_func(y):
return x + y
return inner_func
closure_func = outer_func(10)
print(closure_func(5)) # Output: 15
In the above example, we have defined a function outer_func
that takes an argument x
. Inside outer_func
, we have defined another function inner_func
that takes an argument y
and returns the sum of x
and y
. Finally, outer_func
returns inner_func
. We then call outer_func
with an argument of 10
and assign the result to closure_func
. We can then call closure_func
with an argument of 5
and get the output 15
.
In this example, inner_func
is a closure because it has access to the variable x
in the enclosing scope of outer_func
, even though outer_func
has returned and is no longer executing. Each time we call closure_func
, it “remembers” the value of x
that was passed to outer_func
.
How Closures in Python Work?
In Python, when a function is defined inside another function, it creates a closure. The inner function has access to the variables in the outer function’s scope.
When the outer function returns, the inner function is still able to access those variables because they are “closed over” by the closure.
In our example above, when outer_func
is called with an argument of 10
, it creates a closure that “closes over” the variable x
with a value of 10
. When inner_func
is called with an argument of 5
, it adds 5
to the value of x
and returns the result.
Benefits of Closures
Closures have several benefits in Python programming. They can be used to:
- Create function factories: A function factory is a function that returns another function. Closures can be used to create function factories because they allow you to “remember” the state of the factory function.
- Implement data hiding: Closures can be used to hide data within a function. This is useful when you want to create a private variable that cannot be accessed from outside the function.
- Create decorators: Decorators are a powerful feature in Python that allow you to modify the behavior of functions or classes. Closures can be used to create decorators because they allow you to wrap a function with additional functionality.
Let’s learn the use case for closures in detail.
Function Factory Using Python Closures
A function factory is a function that returns another function. This can be useful when you need to create multiple functions with similar functionality.
Let’s take a look at an example of a function factory:
def multiply_by(x):
def multiplier(n):
return n * x
return multiplier
double = multiply_by(2)
triple = multiply_by(3)
print(double(5)) # Output: 10
print(triple(5)) # Output: 15
In this example, we define a function called multiply_by
that takes an argument x
. multiply_by
returns an inner function called multiplier
that takes an argument n
and returns the product of n
and x
.
Next, we call multiply_by
with the argument 2
, which returns a function that doubles its input. We assign this function to the variable double
.
We then call double
with the argument 5
, which returns 10
.
We repeat the process for triple
, which is a function that triples its input. We call triple
with the argument 5
, which returns 15
.
Decorators Using Closures in Python
Closures are often used to create decorators, which are functions that modify the behavior of other functions. Decorators are a powerful tool in Python, and they can be used to add functionality to existing functions without modifying their code. Here’s an example:
def my_decorator(func):
def wrapper():
print('Something is happening before the function is called.')
func()
print('Something is happening after the function is called.')
return wrapper
@my_decorator
def say_hello():
print('Hello!')
say_hello()
In this example, we define a decorator called my_decorator
. This decorator takes a function as an argument and returns a new function that wraps the original function.
When we apply the @my_decorator
decorator to the say_hello
function, it will modify the behavior of the function by adding a few print statements.
Event Handlers Using Python Closures
Event handlers are functions that are executed in response to an event, such as a button click or a key press.
Let’s take a look at an example of an event handler:
def click_handler(button):
def handler():
print(f"{button} clicked!")
return handler
button1 = click_handler("Button 1")
button2 = click_handler("Button 2")
button1() # Output: "Button 1 clicked!"
button2() # Output: "Button 2 clicked!"
In this example, we define a function called click_handler
that takes an argument button
. click_handler
returns an inner function called handler
that prints a message to the console when called.
Next, we call click_handler
with the argument "Button 1"
, which returns a function that prints "Button 1 clicked!"
when called. We assign this function to the variable button1
.
We then call button1
, which executes the handler
function and prints "Button 1 clicked!"
to the console.
We repeat the process for button2
, which is a function that prints "Button 2 clicked!"
when called.
Create private variables Using Python Closures
Closures can also be used to create private variables in Python. A private variable is a variable that cannot be accessed or modified from outside the function. Here’s an example:
def outer_function():
count = 0
def inner_function():
nonlocal count
count += 1
print(count)
return inner_function
my_func = outer_function()
my_func()
my_func()
In this example, we define an outer function that returns an inner function. The count
variable is a private variable that can only be accessed and modified by the inner function. When we call the my_func
function twice, it will print 1
and 2
.
Memoization Using Closures
Memoization is a technique for caching the results of expensive function calls and returning the cached result when the same inputs occur again. This can improve performance by avoiding unnecessary computation.
Let’s take a look at an example of memoization:
def fibonacci():
cache = {}
def fib(n):
if n in cache:
return cache[n]
if n == 0 or n == 1:
result = n
else:
result = fib(n-1) + fib(n-2)
cache[n] = result
return result
return fib
fib = fibonacci()
print(fib(10)) # Output: 55
In this example, we define a function called fibonacci
that returns an inner function called fib
. fib
implements the Fibonacci sequence recursively.
We also define a cache
dictionary to store the results of previous calls to fib
.
When fib
is called with an argument n
, it first checks if the result for n
is in the cache. If it is, it returns the cached result. Otherwise, it computes the result and stores it in the cache before returning it.
Finally, we call fibonacci
to get the fib
function and assign it to the variable fib
. We then call fib
with the argument 10
, which returns 55
.
Criteria for Closures
To work with closures in Python, there are three key criteria that must be met:
- The presence of nested functions.
- The use of a variable from the outer function in the inner function.
- The outer function must return the inner function.
When these conditions are satisfied, Python utilizes its closure feature. All of the examples provided in this blog fulfill these criteria and demonstrate how Python closures work in practice.
Hope you like it.
Learn more about Python like decorator, generator, inner function, and store web scraping to CSV using Python.