Understanding python dictionary in exec uses global variables instead of locals

I found the following differences between using dictionary concepts and other methods in exec and eval. Thus, the difference is that when using concepts, variables are taken from the argument of the globals, but equivalent code that does not use concepts takes variables from the locals argument.

This was discovered in Python 2.7.3 from the Windows Installer of the Python Software Foundation.

When executing the following code:

locals1 = {"d":{1: 'x', 2: 'y', 3: 'z'}, "test":3} globals1 = dict(globals().items() + [("d", {1: 'a', 2: 'b', 3: 'c'}), ("test", 2)]) exec "new = {key:d[key] for key in d if key != test}" in globals1, locals1 print locals1 

Output:

 {'test': 3, 'new': {1: 'a', 3: 'c'}, 'd': {1: 'x', 2: 'y', 3: 'z'}} 

Note that the dictionary (d) and test value (test) are taken from the globals argument.

When equivalent code is executed:

 locals2 = {"d":{1: 'x', 2: 'y', 3: 'z'}, "test":3} globals2 = dict(globals().items() + [("d", {1: 'a', 2: 'b', 3: 'c'}), ("test", 2)]) exec "new = d.copy(); new.pop(test)" in globals2, locals2 print locals2 

This output is generated:

 {'test': 3, 'new': {1: 'x', 2: 'y'}, 'd': {1: 'x', 2: 'y', 3: 'z'}} 

In this case, the dictionary (d) and the test value (test) are taken from the locals argument.

A further indication that the code execution with understanding will end with a change to the exception not found if the dictionary and / or test value are not included in the global argument, even if they are in the locals argument.

Please note that this is not a question about using exec, and I have good reasons for using exec. The same situation can be demonstrated using eval.

+4
source share
1 answer

This is perfectly correct; understanding of the dictionary is performed as an area of ​​functions. Any variables referenced by a scope that is not defined in that scope are considered global.

You will get the same effect if you used an explicit function in your exec -ed code:

 >>> locals3 = {"d":{1: 'x', 2: 'y', 3: 'z'}, "test":3} >>> globals3 = dict(globals().items() + [("d", {1: 'a', 2: 'b', 3: 'c'}), ("test", 2)]) >>> exec "def f():\n new = d.copy()\n new.pop(test)\n return new\nnew = f()" in globals3, locals3 >>> print locals3 {'test': 3, 'new': {1: 'a', 3: 'c'}, 'd': {1: 'x', 2: 'y', 3: 'z'}, 'f': <function f at 0x106bbcaa0>} 

This is described in the Displays for Kits and Dictionaries section:

Note that understanding is performed in a separate area, so the names assigned in the target list do not “flow” in the covering area.

In Python 2.x, list views do not get their own scope, something that has since been changed in Python 3.

+1
source

Source: https://habr.com/ru/post/1495139/


All Articles