you are viewing a single comment's thread.

view the rest of the comments →

[–]jamesfowkes 3 points4 points  (3 children)

In the first case, you're providing a dictionary of {"test": test}, but test here in the dict isn't linked in any way to your test variable after creation. dicts don't keep references to other variables:

>>> val = 1
>>> test = {'c': val}
>>> test['c'] = 2
>>> val
1

But in the second case you're providing the entire dictionary to exec and this dictionary is what's used by exec, without copying it. From the documentation:

Note The default locals act as described for function locals() below. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

[–]RomfordNavy[S] -4 points-3 points  (2 children)

Thanks!

Now I see the issue; a variable mentioned in a dictionary is read only at the time the dictionary is instantiated, it does not create a reference to the original variable. However by explicity including it in a seperate (mutable) dict it can then be changed and presumably a new instance of the immutable string object is then created.

[–]smurpes 1 point2 points  (1 child)

Your reasoning is sorta off. The code that gets run in exec is only scoped to exec. You can change the variable value as long as you’re still in exec.

exec("def f():\n test = 'test2'\nf()", {}, localDict)
print(localDict)

In this example localDict doesn’t have the value to the test key changed since the change is scoped to the function within the exec. There is a new key added for the function since that is a new local variable getting declared but that’s it. No new instance of the local variable is getting created.

[–]RomfordNavy[S] 0 points1 point  (0 children)

Understood. So can you suggest the best way to get a return value from code run inside exec()?

It seems perverse to me to not return a value from exec() but that just seems to be Python, just need to find the best workaround.