Beazley pg 100 mentions:
>>>python.__closure__
(<cell at 0x67f50: str object at 0x69230>,)
>>>python.__closure__[0].cell_contents
my understanding is that __closure__ is a list but what’s all this
cell stuff and str object?? That looks like a 1-ary tuple?
Closure cells refer to values needed by the function but are taken from the surrounding scope.
When Python compiles a nested function, it notes any variables that it references but are only defined in a parent function (not globals) in the code objects for both the nested function and the parent scope. These are the
co_freevarsandco_cellvarsattributes on the__code__objects of these functions, respectively.Then, when you actually create the nested function (which happens when the parent function is executed), those references are then used to attach a closure to the nested function.
A function closure holds a tuple of cells, one each for each free variable (named in
co_freevars); cells are special references to local variables of a parent scope, that follow the values those local variables point to. This is best illustrated with an example:In the above example, the function
barhas one closure cell, which points tospamin the functionfoo. The cell follows the value ofspam. More importantly, oncefoo()completes andbaris returned, the cell continues to reference the value (the stringeggs) even though the variablespaminsidefoono longer exists.Thus, the above code outputs:
and
b.__closure__[0].cell_contentsis'eggs'.Note that the closure is dereferenced when
bar()is called; the closure doesn’t capture the value here. That makes a difference when you produce nested functions (withlambdaexpressions ordefstatements) that reference the loop variable:The above will print
saladthree times in a row, because all threelambdafunctions reference thespamvariable, not the value it was bound to when the function object was created. By the time theforloop finishes,spamwas bound to'salad', so all three closures will resolve to that value.