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()
.
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.
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.
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