Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - locals() and closure

I can not find an adequate explanation for this behavior.

>>> def a():
...     foo = 0
...     print locals()
...     def b():
...         print locals()
...     b()

>>> a()
{'foo': 0}
{}

But:

>>> def a():
...     foo = 0
...     print locals()
...     def b():
            foo
...         print locals()
...     b()

>>> a()
{'foo': 0}
{'foo': 0}

I understand that in the second case there is a closure, but I can not find a detailed description of what actually is and under what conditions should return the function locals().

like image 505
Veniamin Krol Avatar asked Aug 09 '12 20:08

Veniamin Krol


2 Answers

If you don't assign to foo within the closure, Python resolves it to the foo of the scope one level up (and on up until it finds a foo somewhere or throws an exception).

By mentioning foo within b() in the second example, you put foo into the locals within b(), but it resolves to the foo within the body of a(). If you assign, say, foo = 1 in b(), you would see

 {'foo': 0}
 {'foo': 1}

as the output.

like image 172
Michael Schuller Avatar answered Nov 14 '22 23:11

Michael Schuller


locals() built-in function prints local symbol table which is bound to a code object, and filled up when interpreter receives a name in a source code.

Second example, when disassembled, will contain LOAD_GLOBAL foo bytecode instruction in b function code. This LOAD_GLOBAL instruction will move up the scope, find outer foo name and bind it to the code object by adding name offset into co_names attribute of the closure's (function b) code object.

locals() function prints local symbol table (as was said before, co_names attribute of function's code object).

Read more about code objects here.

like image 32
Rostyslav Dzinko Avatar answered Nov 14 '22 22:11

Rostyslav Dzinko