Closures are often used in function programming. What is a closure, how it is produced, and what problems to solve. Give a literal definition first: A closure is a combination of a function and its associated reference environment (that is, the closure = function + reference environment) (think of the outer function of Erlang passing in a parameter a, the inner function still passes in a parameter B, the inner function uses a and B, and finally returns the inner layer function). This is literally hard to understand, especially for programmers who have been programming with imperative languages. This article will be interpreted in conjunction with the instance code.
What is a function
The earth people know: function is just a piece of executable code, after compiling "cured", each function in memory only one instance, get the function entry point can execute function. In a functional programming language, a function is a first-class citizen, and we do not need a function pointer, as in imperative language, to delegate an action function, and a function can be assigned to a variable as a parameter or return value of another function . Functions can be nested defined, that is, within one function can define another function, with the structure of nested functions, the closure problem arises. Such as:
>>>DefExfunc (n):
Sum=N
DefInsfunc ():
ReturnSum+1
ReturnInsfunc
>>>MyFunc=Exfunc (10)
>>>MyFunc ()
11
>>>< Span style= "color: #000000;" > myanotherfunc=exfunc ( 20)
>>>< Span style= "color: #000000;" > myanotherfunc ()
21
>>> myfunc ()
>>> myanotherfunc ()
21
>>>
In this program, the function insfunc is an inline function of the function Exfunc and is the return value of the Exfunc function. We notice a problem: The local variable referenced in the outer function in the inline function Insfunc Sum,ironpython will handle this problem? Let's take a look at the running results of this code first. When we call the function (MyFunc (), Myanotherfunc ()) that is obtained by invoking the Exfunc function by a different parameter, the resultingresult is isolated, meaning that a new local variable sum is generated and saved each time the Exfunc function is called. In fact, the Exfunc function here is to return a closed packet.
Reference environment
according to the rules of the imperative language, the Exfunc function simply returns the address of the inline function Insfunc, and when the Insfunc function is executed, an error occurs because the sum variable is not found within its scope. In a functional language, when the inline function body refers to variables outside the body, the reference environment and function bodies involved in the definition are packaged into a whole ( closure ) return . The definition of a reference environment is now easy to understand: a reference environment is a collection of all active constraints (the name of a variable and the connection between the object it represents) at a point in the execution of the program. There is no difference between the use of closures and normal function calls.
Since closures package the function and runtime reference environment as a new whole, it solves the problem caused by nesting in function programming. As in the preceding code snippet, a new closure instance is returned each time the Exfunc function is called, and the instances are isolated, containing the different reference environment sites at the time of invocation. Unlike functions, closures can have multiple instances at run time, and different reference environments and the same combination of functions can produce different instances.
A, definition
the closure in Python is defined (interpreted) as: if, in an intrinsic function, a reference is made to a variable in an outer scope (but not at the global scope), the intrinsic function is considered a closure (closure). The definition is relatively straightforward, well understood, and not as pedantic as other definitions (the explanation of the scholarly tastes, in the interpretation of a noun is filled with a lot of other strange nouns, not suitable for beginners). Here is a simple example to illustrate.
>>>def ADDX (x): >> > def adder (y): return x + y >>> return adder > >> C = addx (8) >>> type (c) <type " ' > >>> c.__name__ ' adder >>> C (10)
Combine this simple code and definition to illustrate closures:
If in an intrinsic function: Adder (y) is the intrinsic function,
A reference to a variable that is in an outer scope (but not at the global scope): X is the referenced variable, x is inside the outer scope addx, but not in the global scope,
Then this intrinsic function adder is a closure.
A little more elaborate explanation is that the closure = function Block + the environment when defining the function, Adder is the function block, X is the environment, of course, this environment can have many, more than a simple x.
Second, use closure considerations
1, the outer scope of the local variable cannot be modified in the closure
def foo (): ... = 0 ... def foo1 (): ... = 1 ... Print m ... ... Print m ... Foo1 () ... Print m ... >>> foo () 0 1 0
As can be seen from the execution result, although a variable m is defined in the closure, it does not change the local variable m in the outer function.
2, the following code is a classic error code when using closures in Python
def foo (): = 1 def Bar (): = a + 1 return a return Bar
This procedure is intended to be done by incrementing the variable a every time the closure function is called. But in actual use
>>> C = foo () >>> print C () Traceback (most recent call last): File " <STDIN> " , line 1, in <module> File " <stdin> , line 4, in bar unboundlocalerror:local variable " " referenced before assignment
This is because Python imports all of the closure function bar () to parse its local variables when executing code c = foo (), and the Python rule specifies that all variables on the left side of the assignment statement are local variables, and in the closure bar (), the variable A is at the left of the assignment symbol "=", is considered by Python to be a local variable in bar (). The next time you execute print C (), the program runs to a = a + 1 o'clock, because a has previously been attributed to a local variable in bar (), so Python will find the value of a in bar () to the right of the assignment statement, and the result will be an error if it is not found. The solution is simple.
def foo (): = [1] def Bar (): = a[0] + 1 return a[0] return Bar
Just set a as a container. This is somewhat uncomfortable to use, so after python3, before a = a + 1, use the statement nonloacal A, which explicitly specifies that a is not a local variable of the closure.
3, there is also a prone to error cases are 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
for in range (3): Print i
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.
Flist = [] for in range (3): defprint x + I flist.append (foo) for inch flist: f (2)
Some people may think that the result of this code should be 2,3,4. But the actual result is 4,4,4. This is because Python has not assigned a value to I when I add a function to the Flist list, only when it is executed, and then to find the value of I, at the end of the first for loop, the value of I is 2, so the result of the above code is 4,4,4.
The solution is also very simple, rewrite the definition of the function can be.
for in range (3): defprint x + y flist.append (foo)
Third, the role
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.
Use 1, when the closure is finished, still can maintain the current operating environment.
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.
Origin = [0, 0]#coordinate system origin pointLegal_x = [0, 50]#the legal coordinates of the x-axis directionLegal_y = [0, 50]#the legal coordinates of the y-axis directiondefCreate (pos=origin):defplayer (direction,step):#here should first judge the legitimacy of the parameter direction,step, for example, direction can not go diagonally, step can not be negative, etc. #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. new_x = pos[0] + direction[0]*Step new_y= Pos[1] + direction[1]*Step Pos[0]=new_x pos[1] =new_y#Watch out! pos = [new_x, new_y] cannot be written here, for the reasons mentioned above returnPOSreturnplayer Player= Create ()#Create a pawn player, starting at the origin pointPrintPlayer ([1,0],10)#move 10 steps in the positive direction of the x-axisPrintPlayer ([0,1],20)#move 20 steps in the positive direction of the y-axisPrintPlayer ([ -1,0],10)#10 steps in the negative direction of the x-axis
Output to
[Ten, 0] [ten] 20]
Use 2, closures can be based on the external scope of local variables to get different results, which is a bit like a configuration function, 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.
def Make_filter (Keep): def The_filter (file_name): = Open (file_name) = file.readlines () file.close ( ) if inch i] return Filter_doc return The_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
Filter = Make_filter ("pass") = 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.
Reference: http://www.cnblogs.com/Jifangliang/archive/2008/08/05/1260602.html
Reference: http://blog.csdn.net/marty_fu/article/details/7679297
python-Closure Package Detailed