Closure in Python

Posted by trystan on Mon, 21 Feb 2022 05:37:42 +0100

The art and Tao of Python Programming: Advanced Python language video course
Link to the video course "the art and Tao of Python Programming: Advanced Python language":


Objects are data with methods attached. Closures are functions with data attached.

A Closure is a function object that remembers values in enclosing scopes even if they are not present in memory.

Object refers to the data with corresponding methods; Closures refer to functions with corresponding data. Closure functions can reference variables that are not defined in the current code context. These referenced variables are defined in the code of the enclosing scope of the closure function. Such functions are called closures.

Let's explain it step by step.

First, a nested function is a function defined inside another function. It is important to note that nested functions can access variables that surround the scope. However, in python, they are only read-only. However, you can use the nonlocal keyword explicitly with these variables to modify them.

def transmit_to_space(message):
    "This is the enclosing function"
    def data_transmitter():
        "The nested function"


print(transmit_to_space("Test message"))
Test message

Because in the above example, data_ The transmitter function can access message, so there is no problem working. To demonstrate the use of the nonlocal keyword, consider the following example:

def print_msg(number):
    def printer():
        "Here we are using the nonlocal keyword"

def print_msg(number):
    def printer():
        "Here we are using the nonlocal keyword"
        nonlocal number


If there is no nonlocal keyword, the output will be "3 9", but using it, we get "3 3", that is, we modify the value of the number variable.

Now, we return a function object instead of calling nested functions in it. (remember that functions are objects in Python.)

def transmit_to_space(message):
    "This is the enclosing function"
    def data_transmitter():
        "The nested function"
    return data_transmitter
fun2 = transmit_to_space("Burn the Sun!")
Burn the Sun!

Even if transmit is completed_ to_ For the execution of space (), message is retained. This technique of attaching data to some code even after the end of other original functions is called closure.

Another example:

def pow_later(x):
    y = 2
    def lazy_pow():
        print('calculate pow({}, {})...'.format(x, y))
        return pow(x, y)
    return lazy_pow

We call pow_later pow_later(3), which returns a function object.

my_pow = pow_later(3)
<function __main__.pow_later.<locals>.lazy_pow()>

Then we call the returned function object.

calculate pow(3, 2)...


Obviously, the variable y and the parameter x are pow_ The local variable of the later function. So when you call my_ When pow(), pow_ The later function has returned and its local variables have disappeared. But in fact, even if the external scope pow_later has long disappeared, my_pow() still remembers the values of x and y.

Free variable

If a variable in a function is neither a local variable nor a parameter of the function, the variable is called a free variable of the function.

In short, free variables are variables that are used locally but defined within the enclosing scope.

In our example, x is pow_ Parameter of later, y is pow_ Local variable of later. But in lazy_ In pow, x and y are free variables.

my_pow is actually by calling pow_ The function object returned by later (x) is a closure.

Attention, lazy_pow's closure extends lazy_ The scope of pow function to include the binding of free variables x and y.

Generally speaking, closure is a structure that stores functions with an environment (code block, function object, callable object, etc.). The environment here refers to the information about the bound free variables, especially the value or storage location of the free variables.

For example, after a subsequent function call, a closure is created, returned, and assigned to my_pow.

my_pow = pow_later(3)

Essentially, this closure is a function lazy_pow and the code of free variables x and y together.

Functions without free variables are not closures.

def f(x):
    def g():
    return g

Note that the returned function g has no free variables. Its__ closure__ It's None.

When are closures?

As can be seen from the above example, when a nested function references a value within its enclosing scope, there will be a closure in Python.

The following points summarize the conditions that must be met to create closures in Python:

  • There must be a nested function (function in function)
  • The nested function must refer to a value defined in the enclosing function
  • The enclosing function must return the nested function

When do I use closures?

Closures can avoid using global values and provide some form of data hiding. It can also provide an object-oriented solution to this problem.

Closures can provide an alternative and more elegant solution when there are few methods implemented in a class (in most cases, a method). However, when the number of properties and methods increases, it is best to implement a class.

The following is a simple example where closures may be preferable to defining classes and creating objects.

def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
# Output: 27
# Output: 15
# Output: 30

Closure refers to a function that extends the scope, including non global variables referenced in the function definition body but not defined in the definition body. It can access non global variables defined outside the definition body.

Topics: Python Back-end AI