This may be elementary, but may help me understand namespaces. A good explanation might step through what happens when the function definition is executed, and then what happens later when the function object is executed. Recursion may be complicating things.
The results aren't obvious to me; I would have expected:
locals_1 would contain var; locals_2 would contain var and locals_1; and locals_3 would contain var, locals_1, and locals_2
# A function calls locals() several times, and returns them ...
def func():
var = 'var!'
locals_1 = locals()
locals_2 = locals()
locals_3 = locals()
return locals_1, locals_2, locals_3
# func is called ...
locals_1, locals_2, locals_3 = func()
# display results ...
print 'locals_1:', locals_1
print 'locals_2:', locals_2
print 'locals_3:', locals_3
Here are the results:
locals_1: {'var': 'var!', 'locals_1': {...}, 'locals_2': {...}}
locals_2: {'var': 'var!', 'locals_1': {...}, 'locals_2': {...}}
locals_3: {'var': 'var!', 'locals_1': {...}, 'locals_2': {...}}
The pattern seems to be, with (n) calls to locals, all of
the returned locals-dicts are identical, and they all include
the first (n-1) locals-dicts.
Can someone explain this?
More specifically:
Why does locals_1 include itself?
Why does locals_1 include locals_2? Is locals_1 assigned when func is created, or executed?
And why is locals_3 not included anywhere?
Does "{...}" indicate an 'endless recursion'? Sort of like those photos of mirrors facing each other?
Let's run this code:
def func():
var = 'var!'
locals_1 = locals()
print(id(locals_1), id(locals()), locals())
locals_2 = locals()
print(id(locals_2), id(locals()), locals())
locals_3 = locals()
print(id(locals_3), id(locals()), locals())
return locals_1, locals_2, locals_3
func()
This would be in the output:
44860744 44860744 {'locals_1': {...}, 'var': 'var!'}
44860744 44860744 {'locals_2': {...}, 'locals_1': {...}, 'var': 'var!'}
44860744 44860744 {'locals_2': {...}, 'locals_3': {...}, 'locals_1': {...}, 'var': 'var!'}
locals()
here grows as expected, however you are assigning the reference to locals()
, not the value of locals()
to each variable.
After each assignment locals()
gets changed, but reference does not, so each variable is pointing to the same object. In my output all object id
s are equal, this is the proof.
Longer explanation
These variables has the same link (reference) to that object. Basically, all variables in Python are references (similar concept to pointers).
locals_1 locals_2 locals_3
\ | /
\ | /
V V V
---------------------------------------------
| single locals() object |
---------------------------------------------
They have absolutely no idea what value does locals()
have, they only know where to get it when it's needed (when the variable is used somewhere). Changes on locals()
don't affect those variables.
In the end of you function you're returning three variables, and this is what happening when you're printing them:
print(locals_N) -> 1. Get object referenced in locals_N
2. Return the value of that object
See? So, this is why they have exactly the same value, the one locals()
has at the moment of print
.
If you change locals()
(somehow) again and then run print statements, what would be printed 3 times? Yep, the NEW value of locals()
.
I like your question, really good one.
Yes, locals()
is sort of magic, but with your approach, you will get it soon or later and will love it.
In [1]: a = {"alfa": 1, "beta": 2}
In [2]: b = a
In [3]: b
Out[3]: {'alfa': 1, 'beta': 2}
In [4]: b["gama"] = 3
In [5]: b
Out[5]: {'alfa': 1, 'beta': 2, 'gama': 3}
In [6]: a
Out[6]: {'alfa': 1, 'beta': 2, 'gama': 3}
As you see, a
get changed indirectly at the moment b
got modified, because both a
and b
are pointing to the same data structure in memory.
locals()
is returning dictionary with all local variablesEdit: clarified when is this dict updated
So all local variables existing at the moment of locals()
call are living here. If you make subsequent calls to locals()
, this dictionary is updated at the moment of the call.
Because locals_1
is reference to dictionary of all locally defined variables. As soon as locals_1
becames part of local namespace, it gets part of the dictionary locals()
returned.
The same answer as previous one applies.
This is the most difficult part of your question. After some research I found excellent article about this topic: http://nedbatchelder.com/blog/201211/tricky_locals.html
The fact is, that locals()
returns a dictionary, which contains references to all local variables. But the tricky part is, it is not directly that structure, it is a dictionary, which is only updated at the moment, locals()
is called.
This explains missing locals_3 in your result. All results are pointing to the same dictionary, but it does not get updated after you introduce locals_3
variable.
When I added another print locals()
before return, I found it there, without it not.
Uff.
I would read it as "there is something more". But I think, you are right, that this is a solution for printing recursive data structure. Without such a solution the dictionary could not be really printed in finite amount of time.
There is one idiom, where locals() are shortening your code a lot, in string.format()
name = "frost"
surname = "national"
print "The guy named {name} {surname} got great question.".format(**locals())
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