The following code in Python 2.X prints "a : 2" as you'd expect:
def f():
#a = 1
exec "a = 2" in globals(), locals()
for k,v in locals().items(): print k,":",v
#a = 3
f()
But if you uncomment the "a = 1" then it prints "a : 1", as I didn't expect. Even weirder, if you uncomment the "a = 3" line then it doesn't print anything at all, which I definitely didn't expect (I had a baffling bug that I distilled down to that).
I think the answer is buried in the documentation on locals() and globals(), or maybe in other questions like this but I thought it was worth calling this manifestation out.
I'd love to learn what the Python interpreter is thinking here, as well as suggestions for workarounds.
The old Python 2's exec
would change the bytecode to search both the local and the global namespaces.
As you define the a = 2
in global, this is the one found when a = 1
is commented. When you uncomment a = 3
, this is the a
"found" but not defined yet.
If you read how symbol tables are processed in this great article by Eli Bendersky, you can better understand how local variables are processed.
You shouldn't use exec
for this kind of code (I hope this is not production code) and it will break anyway when you port your code to Py3k:
Python 3's exec
function is no longer a statement and, therefore, can't change the environment it is situated.
Probably I should go directly to the point:
If you are doing all this dynamic naming stuff, you should use a dictionary:
def f():
data = {'a': 1}
data['a'] = 2
if ...:
data['a'] = 3
from locals
function documentation:
Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
checking:
>>> def f():
a = 1
print(locals())
locals()['a']=2
print(a,locals())
>>> f()
{'a': 1}
1 {'a': 1}
So you just cant modify local context through the locals()
function
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