Setting Variables with Exec Inside a Function

Setting variables with exec inside a function

You're almost there. You're trying to modify a global variable so you have to add the global statement:

old_string = "didn't work"
new_string = "worked"

def function():
exec("global old_string; old_string = new_string")
print(old_string)

function()

If you run the following version, you'll see what happened in your version:

old_string = "didn't work"
new_string = "worked"

def function():
_locals = locals()
exec("old_string = new_string", globals(), _locals)
print(old_string)
print(_locals)

function()

output:

didn't work
{'old_string': 'worked'}

The way you ran it, you ended up trying to modify the function's local variables in exec, which is basically undefined behavior. See the warning in the exec docs:

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

and the related warning on locals():

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.

How pass a value to a variable in python function with using exec()?

Python knows several kinds of scope: module global, function local, nonlocal closures, class body. Notably, scope resolution is defined statically at byte code compile time – most importantly, whether names refer to local/nonlocal or global scope cannot be changed.

Of these scopes, only global scope is guaranteed to behave similar to a dict, and as such writeable. The local/nonlocal scope is generally not writeable, and new variables cannot be added to it.

exec will write to the global scope if locals is not passed in; globals must then explicitly be set to its default of globals().

def func():
exec("a='exec'", globals()) # access only global scope
print(a)

a = 'global'
func() # prints exec

However, once a name is local to a function, exec cannot modify it.

def func():
a = 'local' # assignment makes name local
exec("a='exec global'", globals())
exec("a='exec locals'", globals(), locals())
print(a)

a = 'global'
func() # prints local

While a dict-like representation of local/nonlocal scope exists, the interpreter is not required to honour changes to it.

locals()

Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks. Note that at the module level, locals() and globals() are the same dictionary.

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.

Even though exec does take locals as a dict, these are not treated like function locals/nonlocals. Attempts to modify the default locals (the result of locals()) are not defined.

exec()

... If globals and locals are given, they are used for the global and local variables, respectively. If provided, locals can be any mapping object. Remember that at module level, globals and locals are the same dictionary. If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.

Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. ...

Running exec inside function

It's going to damage your function's performance, as well as its maintainability, but if you really want to make your own code so much worse, Python2 (this will not work in Python3, there you need to use the second alternative) gives you "enough rope to shoot yourself in the foot" (;-):

>>> def horror():
... exec "x=23"
... return x
...
>>> print horror()
23

A tad less horrible, of course, would be to exec in a specific dict:

>>> def better():
... d = {}
... exec "x=23" in d
... return d['x']
...
>>> print better()
23

This at least avoids the namespace-pollution of the first approach.

assignment within exec in python

global x = 5

is not valid python code.

If you want to assign to a global variable x, you should write

global x
x = 5

Try changing your code as

global x
eqn1 = "{0} = {1}".format("x",eqn)
x = 0
exec(eqn1, globals())

To modify global variables with exec, you need to use globals() function.

EDIT: Add globals() function.

Use exec to modify global variables in a class

exec() has optional arguments for you to provide the global and local variable contexts.

But you didn't provide them.



Related Topics



Leave a reply



Submit