Python - locals() and closure
Asked Answered
L

2

6

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

Langland answered 9/8, 2012 at 20:39 Comment(4)
If I were you, I'd accept Michael Shuller's answer (the check mark under the upvote/downvote on his comment). Share the love and show appreciation for his efforts!Hymie
@Hymie The answer of Rostyslav Dzinko is depeer.Langland
True! I should have phrased it better: I was trying to say more that you should shower your favor on an answer, rather than necessarily my favorite. But I did, and do still, feel that Michael's answer more directly addressed your question, pointing out that Python searches up-scope for ambiguous values, which was the behavior you demonstrated!Hymie
@Hymie I was interested in the internals. To be honest, I also have not fully satisfied with the answer by Rostyslav Dzinko. I need more details!Langland
P
4

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.

Phylum answered 9/8, 2012 at 20:53 Comment(0)
M
5

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.

Matias answered 9/8, 2012 at 20:43 Comment(1)
Thanks, but i need more internal details :(Langland
P
4

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.

Phylum answered 9/8, 2012 at 20:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.