What is a closure ? Borrow here 《Fluent Python》 The definition of closure in "a closure is function with an extended scope that encompasses non-global variables referenced in the body of the function but not defined there". Simply speaking : Closure = function + Reference to free variables .
So what are free variables (free variables)? In a function , If a variable is neither created inside the function nor is a formal parameter of the function , And it is not a global variable (global variables), Then this variable is a free variable for the function . If you say too much, you might as well give an example :
def outer():
var = 3
def inner():
print(var)
return inner
func = outer()
func() # print 3
var = 5
func() # print 3
In this code , function inner and var It's a closure ,var about inner It's a free variable . You can see var Not in inner Created in the , But in outer Created in . So the function inner How to store variables var Well ? The answer is inner.__code__.co_freevars and inner.__closure__, The former records the name of the free variable , The latter records the value of the free variable .
print func.__code__.co_freevars # ('var',)
print func.__closure__[0].cell_contents # 3
Closure unit refers to the value required by the function , But from the surrounding area .
When Python When compiling nested functions , It will note the parent functions that it references but only in the nested functions and code objects of the parent scope ( It's not a global variable ) Any variable defined in . These are, respectively, of these functions __code__ On the object co_freevars and co_cellvars attribute .
then , When you actually create nested functions ( Occurs when the parent function is executed ) when , These references will be used to attach closures to nested functions .
Function closure contains a unit tuple , Each cell corresponds to a free variable ( With co_freevars name ); A cell is a special reference to a local variable of the parent scope , It follows the values that those local variables point to . It is best to illustrate this with an example :
def foo():
def bar():
print(spam)
spam = 'ham'
bar()
spam = 'eggs'
bar()
return bar
b = foo()
b()
In the example above , function bar There is a closure unit , It points to a function foo Spam in . Cells follow spam values . what's more , once foo() Complete and return bar, Even if foo The variables in the spam No longer exist , The cell will continue to reference the value ( String egg ).
therefore , The above code output :
>>> b=foo()
ham
eggs
>>> b()
eggs
here , b.__closure__[0].cell_contents
yes 'eggs'
.
Please note that , call bar() Will dereference the closure ; Closures do not capture the value here . When you generate nested functions that reference circular variables ( Use lambda Expression or def sentence ) when , This will be different :
def foo():
bar = []
for spam in ('ham', 'eggs', 'salad'):
bar.append(lambda: spam)
return bar
for bar in foo():
print bar()
Above he will print continuously 3 Secondary salad , Because all three lambda Functions refer to spam Variable , Instead of the value bound when the function object is created . When for At the end of the loop , Spam is bound to “ salad ”, So all three closures will resolve to this value .
>>>python.__closure__
(<cell at 0x67f50: str object at 0x69230>,)
>>>python.__closure__[0].cell_contents