54

I just started self teaching Python, and I need a little help with this script:

old_string = "didnt work"   
new_string = "worked"

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

function()

I want to get it so old_string = "worked".

2
  • 1
    What's the point of this? Why do you want to use exec here? Commented Apr 19, 2014 at 9:30
  • 14
    "I just started self teaching Python.." sounds like they're is just trying to wrap their head around a new language... Commented Apr 19, 2014 at 9:36

2 Answers 2

50

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Is there a way to modify it in the scope of the calling function?
@SarcasticSully there is no calling function here.. If you wonder about something tangentially associated with the question, or answer, you should ask a new question (with the proper context, code samples, etc.) Leaving new questions in comments of 3 year old answers isn't likely to be helpful for anyone...
Rather than add a global statement, you can simply set the namespaces: exec('old_string = new_string', globals(), globals()).
@MartijnPieters if you do that (exec('..', globals(), globals())) any variable created in the exec becomes a global -- probably not what you want?
Yes, and that could be the goal. Most people forget about the ability to specify the namespaces (including new dictionaries), if you don’t want all names as globals using a custom namespace and then extracting what you need afterwards might be the better option anyway.
|
14

An alternative way of having exec update your global variables from inside a function is to pass globals() into it.

>>> def function(command):
...    exec(command, globals())
...
>>> x = 1
>>> function('x += 1')
>>> print(x)
2

Unlike locals(), updating the globals() dictionary is expected always to update the corresponding global variables.

4 Comments

Try function("[t for t in range(5)]"), then print(t)... Maybe too many unintended consequences?
@thebjorn I get NameError: name 't' is not defined, which is what I would expect. Are you using an old version of Python before they fixed the variables-escaping-comprehensions bug?
Yes 2.7 all the way! (sigh). Did they fix the for-loop variable escape too?
No, if I understand you correctly. I think that's intended behaviour.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.