One of the features of Python is the ability to use closures. A closure is a function object that remembers values in the enclosing scope, even if they are not present in memory. This allows for the creation of functions that can retain state information between calls. In this article, we will explore what a Python closure is, how it works, and provide examples of how to use it.

## What is a Python Closure?

A closure is a function that has access to variables in its enclosing lexical scope, even when the function is called outside that scope. In other words, a closure is a function that remembers the values from its enclosing scope, even after the scope has been destroyed. Closures are created by defining a function inside another function and returning the inner function. The returned function can then be called, and it will still have access to the variables in the outer function.

## How Python Closure Works

When a function is defined inside another function, it has access to the variables in the outer function’s scope. This is because the inner function is created at the time the outer function is called. The inner function then “closes over” the variables in the outer function’s scope and retains a reference to them.

When the outer function returns, the inner function is still able to access the variables in the outer function’s scope. This is because the inner function retains a reference to the outer function’s scope.

## Examples of How to Use Python Closure

### Example 1: Simple Closure

```
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
print(closure(5)) # Output: 15
```

In this example, we define an outer function that takes a parameter x. The outer function defines an inner function that takes a parameter y. The inner function returns the sum of x and y. The outer function then returns the inner function.

We then call the outer function with a value of 10, which returns the inner function. We assign the returned inner function to a variable called closure. We can then call the closure function with a value of 5, which returns 15.

### Example 2: Closure with Non-Local Variables

```
def outer_function(x):
def inner_function(y):
nonlocal x
x += 1
return x + y
return inner_function
closure = outer_function(10)
print(closure(5)) # Output: 16
print(closure(10)) # Output: 18
```

In this example, we define an outer function that takes a parameter x. The outer function defines an inner function that takes a parameter y. The inner function uses the `nonlocal`

keyword to indicate that it will modify the value of x. The inner function increments the value of x by 1, and then returns the sum of x and y. The outer function then returns the inner function.

We then call the outer function with a value of 10, which returns the inner function. We assign the returned inner function to a variable called closure. We can then call the closure function with a value of 5, which returns 16. We can then call the closure function with a value of 10, which returns 18. The value of x is retained between calls to the closure function.

### Example 3: Closure with Default Parameter

```
def outer_function(x):
def inner_function(y, z=x):
return x + y + z
return inner_function
closure = outer_function(10)
print(closure(5)) # Output: 30
```

In this example, we define an outer function that takes a parameter x. The outer function defines an inner function that takes a parameter y and a default parameter z equal to x. The inner function returns the sum of x, y, and z. The outer function then returns the inner function.

We then call the outer function with a value of 10, which returns the inner function. We assign the returned inner function to a variable called closure. We can then call the closure function with a value of 5, which returns 30. The value of x is retained between calls to the closure function.

### Example 4: Closure with Lambda Function

```
def outer_function(x):
return lambda y: x + y
closure = outer_function(10)
print(closure(5)) # Output: 15
```

In this example, we define an outer function that takes a parameter x. The outer function returns a lambda function that takes a parameter y. The lambda function returns the sum of x and y.

We then call the outer function with a value of 10, which returns the lambda function. We assign the returned lambda function to a variable called closure. We can then call the closure function with a value of 5, which returns 15.

### Example 5: Closure with Decorator

```
def outer_function(function):
def inner_function(*args, **kwargs):
print("Before function call")
result = function(*args, **kwargs)
print("After function call")
return result
return inner_function
@outer_function
def add_numbers(x, y):
return x + y
print(add_numbers(3, 5)) # Output: Before function call, After function call, 8
```

In this example, we define an outer function that takes a function as a parameter. The outer function defines an inner function that takes any number of positional and keyword arguments. The inner function prints “Before function call”, calls the passed-in function with the arguments, prints “After function call”, and returns the result of the function call. The outer function then returns the inner function.

We then define a function called `add_numbers`

that takes two parameters x and y. We decorate the `add_numbers`

function with the `outer_function`

decorator. We can then call the `add_numbers`

function with values of 3 and 5, which prints “Before function call”, returns 8, and prints “After function call”.

## Conclusion

In conclusion, Python closure is a powerful feature that allows for the creation of functions that can retain state information between calls. Closures are created by defining a function inside another function and returning the inner function. The returned function can then be called, and it will still have access to the variables in the outer function.

In this article, we explored what a Python closure is, how it works, and provided examples of how to use it. We covered simple closures, closures with non-local variables, closures with default parameters, closures with lambda functions, and closures with decorators. By understanding how to use Python closure, you can write more efficient and effective code.