1. Definition
Closure is an important grammatical structure of functional programming, and functional programming is a programming paradigm (both procedural programming and object-oriented programming are also programming paradigms). In process-oriented programming, we have seen functions (function), and in object-oriented programming we have seen objects (object). The fundamental purpose of functions and objects is to organize the code in some logical way and to improve the code's repeatability (reusability). Closures are also a structure for organizing code, which also improves the reusable nature of code.
The way the closures are implemented in different programming languages is different, and in Python, in the form of presentation, the intrinsic function is considered a closure (closure) If a reference is made to a variable in the outer scope (but not at the global scope) in an intrinsic function.
As an example:
1 def outer (x): 2 def Inner (y): 3 return x + y4 return
Combine this simple code and definition to illustrate closures:
Inner (y) is the intrinsic function that references variables in the outer scope (but not at the global scope): X is the referenced variable, x is inside the outer scope outer, but not in the global scope, the intrinsic function inner is a closure.
A little more elaborate explanation is that the closure = function Block + the environment when defining the function, inner is the function block, X is the environment, of course, this environment can have many, more than a simple x.
A inner function is defined in the function outer, the inner function accesses the (parameter) variable of the external function outer, and returns the inner function as the return value to the outer function.
1 A = outer (2)2print('function:'3 Print('result:', A (3))
In the code above, A is a function, and the result of the code execution is:
From the results we are not difficult to see, a is a function inner rather than outer, this is a bit around, but it is not difficult to understand, because return is returned is the inner function.
1 Print ('a.func_name', A.func_name)
The output is:
The result of calling function A is to add the value of the passed-in parameter.
The above is the same as this sentence:print(‘result:‘,outer(2)(3))
2. Places to note with closures 2.1 Closures cannot modify local variables of an external function
If Innerfunc can modify the value of X, the value of X will change before and after, but the result is:
The value of x has changed in Innerfunc, but the value of x in Outerfunc has not changed.
Let's look at one more example
2.2 Closures cannot directly access local variables of external functions
1 def outer (): 2 3 def # The above row of x relative inner function is a local variable outside the function (non-global variable) 4 x *= x5 return x6 return inner 78 outer () ()
Operation will be error:
The workaround:
1. There is no direct workaround prior to Python3, only indirectly through the container type, because the container type is not stored in the stack space, the inner function can be accessed.
1 def outer (): 2 x = [53 def4 x[0] *= x[0]5 return X[0] 6 return 78Print(outer ()) #
The
2.python3 is addressed by the Nonlocal keyword, which explicitly specifies that a is not a local variable of a closure.
1 def outer (): 2 3 def 4 # declare x as non-local variable 5 x *= x6 return x 7 return 89Print(outer () ())
Concept of domain not included in 2.3python loops
There is also an error prone case is often mentioned in the introduction of Python closure, I have never felt that this error and closure has much to do with the relationship, but it is indeed in Python functional programming is easy to make a mistake, I would like to introduce here. Let's look at the following code
1 for in range (3): 2print
In the program, this kind of loop is often present, the problem of Python is that, when the loop is over, the temporary variable i in the loop body will not be destroyed, but continue to exist in the execution environment. Another python phenomenon is that Python's function is only executed to find the value of the variable in the function body.
1 flist = [] 2 for in range (3): 3 defPrint x +4 flist.append (foo) 5for in flist: 6
Some people may think that the result of this code should be 2,3,4. But the actual result is 4,4,4. Loop does not have a domain concept in Python, and when Flist adds Func to the list, it does not save the value of I, but when it executes F (2), when the loop is over, the value of I is 2, so the result is 4.
The solution is also very simple, rewrite the definition of the function can be.
for in range (3): defprint x + y
Another example:
The problem to note is that the returned function is not executed immediately, but only when it is called. f()
Let's look at an example:
1 function count () {2var arr = [];3 for(var i=1; i<=3; i++) {4 Arr.push (function () {5 returnIi;6 });7 }8 returnarr;9 }Ten Onevar results =count (); Avar f1 =Results[0]; -var F2 = results[1]; -var f3 = results[2];
In the example above, each loop creates a new function, and then adds the 3 created functions to one Array
.
You may think that the call f1()
, f2()
and the f3()
result should be 1
,, but the 4
9
actual result is:
1 F1 (); 2 f2 (); 3 f3 (); 16
All of them 16
! The reason is that the returned function refers to the variable i
, but it is not executed immediately. When all 3 functions are returned, the variables they refer to are i
already turned 4
, so the end result is 16
.
One thing to keep in mind when returning closures is that the return function does not refer to any loop variables, or to subsequent variables that change.
What if you must refer to a loop variable? The method is to create a function that binds the current value of the loop variable with the parameter of the function, regardless of how the loop variable is subsequently changed, and the value that is bound to the function parameter remains the same:
1 function count () {2var arr = [];3 for(var i=1; i<=3; i++) {4 Arr.push ((function (n) {5 returnfunction () {6 returnn *N;7 }8 }) (i));9 }Ten returnarr; One } A -var results =count (); -var f1 =Results[0]; thevar F2 = results[1]; -var F3 = Results[2]; - -F1 (); 1 +F2 (); 4 -F3 (); 9
Note that there is a syntax for "create an anonymous function and execute it immediately":
1 (function (x) {2 return x * x; 3 }) (3); 9
In theory, creating an anonymous function and executing it immediately can be written like this:
1 return x * x} (3);
However, due to the problem of JavaScript parsing, syntaxerror errors are reported, so you need to enclose the entire function definition in parentheses:
1 return x * x}) (3);
In general, an anonymous function that executes immediately can take the function body apart, which is generally the case:
1 (function (x) {2 return x * x; 3 }) (3);
3. The role of closures
Having said so much, someone has to ask, what is the use of this closure in the actual development? Closures are mainly used in the functional development process. The following are the main uses of two types of closures.
Purpose 1: When the closure has been executed, the current operating environment can still be maintained.
For example, if you want the result of each execution of the function, it is based on the last running result of the function. I illustrate this with an example of a board game like this. Assuming the checkerboard size is 50*50 and the upper-left corner is the coordinate system origin (0,0), I need a function that receives 2 parameters, namely direction (direction), step (step), which controls the movement of the pieces. The new coordinates of the chess piece movement are in addition to the direction and the step length, of course, according to the original coordinate point, the closure can be used to maintain the original position of the piece of the coordinates.
1Origin =[0, 0]2Legal_x = [0, 50] 3Legal_y = [0, 50] 4 defCreate (pos=origin):5 defplayer (direction,step):6 #here should first judge the legitimacy of the parameter direction,step, for example, direction can not go diagonally, step can not be negative, etc.7 #then also to the new generation of x, y coordinates of the legitimacy of the judgment, here is mainly to introduce closures, it is not written in detail. 8new_x = pos[0] + direction[0]*Step9New_y = pos[1] + direction[1]*StepTenPos[0] =new_x OnePOS[1] =new_y A #Watch out! pos = [new_x, new_y] cannot be written here, because parameter variables cannot be modified, and pos[] is the solution to the container class - returnPOS - returnplayer the -Player = Create ()#Create a pawn player, starting at the origin point - PrintPlayer ([1,0],10)#move 10 steps in the positive direction of the x-axis - PrintPlayer ([0,1],20)#move 20 steps in the positive direction of the y-axis + PrintPlayer ([ -1,0],10)#10 steps in the negative direction of the x-axis
The output is:
1 [2 [ten] 3
Purpose 2: Closures can get different results based on local variables of the outer scope
This is a bit like the function of a similar configuration, we can modify the external variables, closures according to this variable to show a different function. For example, sometimes we need to analyze the special lines of some files to extract these special lines first.
1 defMake_filter (keep):2 defThe_filter (file_name):3File =Open (file_name)4Lines =File.readlines ()5 file.close ()6Filter_doc = [i forIinchLinesifKeepinchi]7 returnFilter_doc8 returnThe_filter
If we need to get a line with the "pass" keyword in the file "Result.txt", you can use the example program like this
1 filter = Make_filter ("pass") Filter_result = Filter ("result.txt "
The above two usage scenarios, with object-oriented also can be very simple implementation, but in Python for functional programming, the closure of data persistence and configuration to produce different functions, it is very helpful.
Understanding closures in Python