The assignment order matters unexpectedly with "exec expr in globals (), locals ()"

The following code in Python 2.X prints "a: 2" as you expected:

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 "a = 1", then it prints "a: 1", as I did not expect. Even stranger, if you uncomment the line "a = 3", then it does not print anything, which I definitely did not expect (I had an incomprehensible error, which I guessed).

I think the answer is similar to the documentation for locals () and globals (), or maybe other questions like this , but I thought it should be called a manifest.

I would like to know what the Python interpreter interprets here, as well as suggestions for workarounds.

+7
source share
2 answers

Old Python 2 exec will change the bytecode to search for both local and global namespaces.

As you define a = 2 globally, this is the one that is discovered when commenting on a = 1 . When you uncomment a = 3 , it is a "found", but not yet defined.

If you read how character tables are handled in this great article by Eli Bendersky , you can better understand how local variables are handled.

You should not use exec for this type of code (I hope this is not production code), and it will break anyway when porting your code to Py3k:

The Python 3 exec function is no longer an operator and therefore cannot change the environment in which it resides.


Perhaps I should go directly to the point:

If you do all this dynamic naming, you should use a dictionary:

 def f(): data = {'a': 1} data['a'] = 2 if ...: data['a'] = 3 
+2
source

of locals function documentation :

Note: The contents of this dictionary should not be changed; changes may not affect the values ​​of local and free variables used by the interpreter.

check:

 >>> def f(): a = 1 print(locals()) locals()['a']=2 print(a,locals()) >>> f() {'a': 1} 1 {'a': 1} 

Thus, you simply cannot change the local context using the locals() function

+1
source

All Articles