__closure__ magic function in Python



Understanding Closures in Python

In Python, functions are treated as first-class citizens. This means you can assign them to variables, pass them as arguments to other functions, or even return them from other functions.

A closure is a special kind of inner function that remembers variables from its enclosing (outer) function's scope, even after the outer function has finished running. This allows the inner function to retain access to those variables and behave as if the outer scope still exists.

To form a closure in Python, it is necessary to meet the following two conditions ?

  • There must be a nested (inner) function that uses variables defined in the outer function.
  • The outer function must return the inner function.

This behavior allows closures to "carry" the environment in which they were created, and they can act like function factories by generating customized behavior based on the enclosed variables.

Python __closure__ Attribute

When a function forms a closure, Python stores the captured variables using a special attribute called __closure__. This attribute is a tuple of cell objects, where each cell contains one variable captured from the outer function's scope.

Each cell object represents a variable captured from the outer scope, and the value inside each cell can be accessed using the cell_contents attribute.

Example

In this example, the variable x is captured by the inner function and stored in the __closure__ attribute of the returned function f. The actual value can be accessed using cell_contents attribute ?

def outer(x):
   def inner():
      return x
   return inner

f = outer(10)
print(f.__closure__)    # Tuple of cell objects
print(f.__closure__[0].cell_contents)

We get the output as shown below ?

(<cell at 0x7f446bddebf0: int object at 0xb35ac8>,)
10

If the inner function does not capture any variables from the outer function, then its __closure__ attribute will simply be None.

This mechanism is what allows closures in Python to remember and access the values of variables that were in scope when the function was created, even long after that scope has gone.

Creating a Closure with an Outer Variable

We can create a closure by defining a nested function that uses the variable from the outer function and returning the inner function. This allows the inner function to retain the value of the outer variable.

Example

In this example, we define a function outer_function that returns an inner function. The inner function uses the variable x from the outer scope, which forms a closure ?

# Define an outer function that returns an inner function
def outer_function(x):
   def inner_function(y):
      # uses 'x' from outer function
      return x + y
   return inner_function

# creates a closure with x = 10   
closure = outer_function(10)

# calls inner_function with y = 5
result = closure(5)
print(result)

Following is the output of the above code ?

15

Using __closure__ to Access Enclosed Variables

We can examine what values a closure has captured from the outer function using the __closure__ attribute. These values are stored in cell objects, and we can view their contents using the cell_contents attribute.

Example

In this example, we inspect the internal state of a closure using its __closure__ attribute. The closure tuple contains one cell object holding the value 10, which is the variable x from the outer scope ?

# Define a function that forms a closure
def outer_function(x):
   def inner_function(y):
      return x + y
   return inner_function

# Create the closure with x = 10
closure = outer_function(10)

# Inspect the closure's internal cells
print(closure.__closure__)  # Tuple of cell objects
print(closure.__closure__[0].cell_contents) # Value of 'x' inside the cell

We get the output as shown below ?

(<cell at 0x7fb45fa40310: int object at 0x7fb45fb18210>,)
10

Conclusion

The __closure__ attribute in Python allows inner functions to remember and access variables from their outer scope even after the outer function has finished executing. It plays an important role in how closures work by storing these captured variables inside cell objects.

Updated on: 2023-05-08T13:32:18+05:30

969 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements