Where does Python keep the function name closure binding?

Recently, I understand the concept of closing a function.

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 I understand it, the goal of closing a function is to keep an active reference to an object in order to avoid garbage collection of this object. This is why the following works perfectly:

 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 (always, as I understand it) before executing the inner function, Python rebuilds the locals variable dictionary. This dictionary will contain:

  • function closure names associated with their cell contents
  • function parameter names associated with their default value or a given parameter (and it can overwrite use case names)

The question is, where does Python store the closure name binding? I canโ€™t find anything.

Note: function 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 
+6
source share
2 answers

It depends on the python implementation. I assume you mean CPython.

__code__ (or func_code ) has the co_freevars attribute, which contains the name of all non-local variables (they are called โ€œfree varsโ€, as if the python function was a logical formula in which arguments and local variables are quantitative variables)

From these various attributes, you can get the mapping of local and non-local names to cells.

 In [35]: function.__code__.co_freevars Out[35]: ('somevar',) 

The co_varnames attribute lists all the names of a local definition:

 In [36]: function.__code__.co_varnames Out[36]: () In [37]: def outer(): ...: somevar = [] ...: def inner(): ...: x = 1 ...: somevar.append(5) ...: return somevar ...: return inner ...: ...: function = outer() In [38]: function.__code__.co_varnames Out[38]: ('x',) 

So far, co_cellvars says which local names are used by internal functions:

 In [43]: outer.__code__.co_cellvars Out[43]: ('somevar',) 
+5
source

Fortunately for us, functions in Python are first class objects. Therefore, we can get a little more information about closing by checking function objects. And all Python functions have a close attribute, which allows us to examine the included variables associated with the closure function.

 >>> def f(): ... pass ... >>> repr(f); repr(f.__closure__) '<function f at 0x0153A330>' 'None' 
-1
source

All Articles