So recently I understand the concept of function closure.
def outer():
somevar = []
assert "somevar" in locals() and not "somevar" in globals()
def inner():
assert "somevar" in locals() and not "somevar" in globals()
somevar.append(5)
return somevar
return inner
function = outer()
somevar_returned = function()
assert id(somevar_returned) == id(function.func_closure[0].cell_contents)
As much as I understand, the objective of function closure is to keep an active reference to the object, in order to avoid garbage collection of this object. This is why the following works fine :
del outer
somevar_returned_2 = function()
assert id(somevar_returned) == id(function.func_closure[0].cell_contents)
assert id(somevar_returned) == id(somevar_returned_2)
The thing is (always as much as I understood) before the execution of the inner
function, Python rebuild the locals variables dictionary. This dictionary will contains :
The question is where do Python store the name binding of the closure ? I can't find it anywhere.
Note: the function's attributes :
>>> print "\n".join("%-16s : %s" % (e, getattr(function, e)) for e in dir(function) if not e.startswith("_") and e != "func_globals")
func_closure : (<cell at 0x2b919f6bc050: list object at [...]>,)
func_code : <code object inner at [...], file "<stdin>", line 4>
func_defaults : None
func_dict : {}
func_doc : None
func_name : inner
This depends on the python implementation. I assume you mean CPython.
The __code__
(or func_code
) has a co_freevars
attribute that contains the name of all non-local variables (they are called "free vars" as if a python function was a logical formula where the arguments and local variables are quantified variables)
From these various attribute you can obtain a mapping from local and non-local names to cells.
In [35]: function.__code__.co_freevars
Out[35]: ('somevar',)
The co_varnames
attribute lists all locally define names:
In [36]: function.__code__.co_varnames
Out[36]: ()
In [37]: def outer():
...: somevar = ["stackoverflow"]
...: def inner():
...: x = 1
...: somevar.append(5)
...: return somevar
...: return inner
...:
...: function = outer()
In [38]: function.__code__.co_varnames
Out[38]: ('x',)
While co_cellvars
says which local names are used by inner functions:
In [43]: outer.__code__.co_cellvars
Out[43]: ('somevar',)
All closure functions have __closure__
attribute. This attribute returns a tuple of cell objects. And The cell object has cell_contents
attribute which stores the value of variable.
In [44]: function.__closure__
Out[44]: (<cell at 0x7f4e06b002b8: list object at 0x7f4e06b522c8>,)
In [45]: function.__closure__[0].cell_contents
Out[45]: ["stackoverflow"]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With