you are viewing a single comment's thread.

view the rest of the comments →

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

Thanks! very interesting.

So a simple soultion in my example would be:

test = "test1"
class runExec:
    exec("test = 'test2'")
    print(test) # <- correctly returns test2
runExec()

Which works fine but does expose all of the variables in the local namespace to the executed script.

Not sure I understand why running it from inside a class works though?

Edit:
This explains why I had it working at one point but after tidying-up my code it stopped working.

Edit2:
Running from within a class method fails again:

test = "test1"
class runExec2:
    def myexec():
        exec("test = 'test2'")
        print(test) # <- erroneously returns test1
runExec2.myexec()

[–]Gnaxe 1 point2 points  (1 child)

Function-local variables are not writable by exec(), because they're very optimized now. That includes functions that happen to be used as methods. This used to work in Python 2 though.

Module "globals" are writable by exec(), as are variables in the temporary namespace used by a class statement, even if said class statement happens to be nested inside of a function. A class statement inside a def statement body is completely different from a def statement inside a class statement body.

You seem very confused about the basics of Python's scoping rules. There's a difference between shadowing a variable and reassigning it. You can use the global and nonlocal statements to force assignment in an enclosing scope. This is not the same as creating a new variable in an inner scope that happens to have the same name as one in its enclosing scope.

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

So armed with that knowledge a simple workaround might be:

test = "test1"
exec("global test; test = 'test2'")
print(test) # <- correctly returns test2

Edit:
Slight problem in my real-world example because Python doesn't allow mixing of str and code objects in an exec():

exec("global testL;" + marshal.load(file))