5

While exploring some solutions to my previous question about the inner workings of Python scope, I learned about the __closure__ attribute. It seems that Python uses this attribute to access variables defined in an outer scope from within a nested function.

We can see this in action by doing the following:

def foo():
    x = 5
    def bar(): 
        print(x)
        print(*(cell.cell_contents for cell in bar.__closure__))
    bar()
foo()

This shows two enclosed values, 5 and the function bar itself.

What I don't understand is how this works - since, the __closure__ attribute merely contains a tuple of cells which store the enclosed values. But there's no information about the enclosed variables names - (i.e. the cells are stored in a tuple, not a dict). So how does Python know the names of the variables which have been enclosed?

Community
  • 1
  • 1
Channel72
  • 24,139
  • 32
  • 108
  • 180
  • See also: [Where does Python store the name binding of function closure? - Stack Overflow](https://stackoverflow.com/questions/32221063/where-does-python-store-the-name-binding-of-function-closure) – user202729 Dec 05 '21 at 06:58

1 Answers1

9

The python compiled code uses indices; the variables are tied to an index into the cells structure.

>>> def foo():
...     x = 5
...     def bar():
...         return x
...     return bar
... 
>>> bar = foo()
>>> import dis
>>> dis.dis(bar)
  4           0 LOAD_DEREF               0 (x) 
              3 RETURN_VALUE         

The LOAD_DEREF bytecode refences the first cell value.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • To clarify further, the Python compiler knows perfectly well the names of the variables involved, but this information is not needed by the compiled bytecode. Local variables and function arguments are handled in a similar way, as are constants used in a function. – kindall Sep 05 '12 at 15:28