Python delves into closures

  • 2020-04-02 14:02:22
  • OfStack

Closure is an important syntactic structure in functional programming. Functional programming is a programming paradigm (both procedural and object-oriented programming are programming paradigms). In procedural programming, we've seen functions; In object-oriented programming, we've seen objects. The fundamental purpose of functions and objects is to organize the code in a logical way and improve the reusability of the code. Closures are also a structure for organizing code, which also increases the repeatability of code.

Different languages implement closures in different ways. Python is based on function objects and provides support for the syntax structure of closures (we have seen Python implement special syntax using objects many times in special methods and multi-paradigms). Everything in Python is an object, and the syntax of a function is an object. In a function object, we use the function object as if it were a normal object, such as changing the name of the function object, or passing the function object as an argument.

The scope of a function object

Like any other object, a function object has a scope that it can live within, which is the scope of the function object. Function objects are defined using the def statement and are scoped at the same level as the def. For example, the function line that we defined within the membership of the line_conf function is called only within the membership of the line_conf function.


def line_conf():
    def line(x):
        return 2*x+1
    print(line(5))   # within the scope
line_conf()
print(line(5))       # out of the scope

The line function defines a line (y = 2x + 1). As you can see, the line function can be called in line_conf(), but calling line outside scope will have the following error:

NameError: name 'line' is not defined

Indicates that you are already out of scope.

Similarly, if you define functions using lambda, the scope of the function object is the same as the scale of the lambda.

closure

A function is an object, so it can be returned as a result of a function.


def line_conf():
    def line(x):
        return 2*x+1
    return line       # return a function object my_line = line_conf()
print(my_line(5))      

The above code runs successfully. The return result of line_conf is assigned to the line object. The code above will print 11.

What happens if the definition of line() references an external variable?


def line_conf():
    b = 15
    def line(x):
        return 2*x+b
    return line       # return a function object b = 5
my_line = line_conf()
print(my_line(5))      

We can see that the top-level variable b is referenced in the subordinate program block defined by line, but the information of b exists outside the definition of line (the definition of b is not in the subordinate program block of line). We call b the environment variable of line. In fact, when line is the return value of line_conf, the value of b is already included in line (although b is not part of line).

The code above will print 25, which means that the b value that line references is the b value that the function object is defined to refer to, not the b value used.

When a function and its environment variables are combined, they form a closure. In Python, a closure is a function object that contains the values of an environment variable. The value of the environment variable is saved in the s _closure__ property of the function object. For example, the following code:


def line_conf():
    b = 15
    def line(x):
        return 2*x+b
    return line       # return a function object b = 5
my_line = line_conf()
print(my_line.__closure__)
print(my_line.__closure__[0].cell_contents)

S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. Each element in this tuple is an object of type cell. We see that the first cell contains the integer 15, which is the value of the environment variable b when we created the closure.

Here's a practical example of a closure:


def line_conf(a, b):
    def line(x):
        return ax + b
    return line line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5), line2(5))

In this example, the function line and the environment variables a and b form closures. When we create the closure, we specify the values of the two environment variables through the parameters a and b of line_conf, thus determining the final form of the function (y = x + 1 and y = 4x + 5). All we need to do is change the parameters a and b, and we can get different lines. From this, we can see that closures can also improve code reusability.

If we don't have closures, we need to say a,b,x every time we create a line function. In this way, we need more parameter passing and less portability of the code. Using closures, we actually create a functional. The line function defines a function with a broad meaning. Some aspects of the function have been determined (it must be a line), but others (such as the a and b arguments are to be determined). We then determine the final function as a closure based on the arguments passed by line_conf.

Closures and parallel operations

Closures effectively reduce the number of arguments a function needs to define. This has important implications for parallel operations. In the context of parallel computing, we can make each computer responsible for a function, and then connect the output of one computer with the input of the next computer. Ultimately, we work like an assembly line, feeding data from one end of a cluster of computers in series and outputting data from the other. This scenario works best for functions with only one parameter input. Closures do this.

Parallel operations are called hot spots. This is an important reason why functional programming is hot again. Functional programming has been around since the 1950s, but it's not widely used. However, the pipelined work parallel clustering process we described above is a good fit for functional programming. Due to the natural advantages of functional programming, more and more languages are adding support for the functional programming paradigm.


Related articles: