4

I'm trying to create a custom python interpreter type application. I'm using exec statement (in Python 2.7.6) to execute given code but globals aren't working quite as expected. Could someone explain why this does not work:

def print_x():
    print(x)


g = {'x': 10, 'print_x': print_x}
l = {}

exec('print_x()', g, l)

The result (whether the print_x function is in g or l), is an error:

NameError: global name 'x' is not defined

So, do the globals passed to exec not carry over to called functions?

jordanwh
  • 43
  • 3
  • So exec does not know how to parse your dictionary g – dmitryro Jun 18 '16 at 04:40
  • But I could use exec('print(x)', g, l) just fine. It just doesn't work with the print_x function. – jordanwh Jun 18 '16 at 04:41
  • http://stackoverflow.com/questions/2904274/globals-and-locals-in-python-exec - seems similar to your case – dmitryro Jun 18 '16 at 04:43
  • Thank you for that link. It is similar but not quite the same as my program. I have now tried printing out globals() and locals() in the print_x() function and sure enough, 'x' is not there. I'm just not quite sure why that is. – jordanwh Jun 18 '16 at 04:50

1 Answers1

3

The x inside the function is picked up from the globals of the namespace where the function is defined. However, you're calling it in a different namespace. This isn't too different from having multiple modules:

# foo.py
def print_x():
    print(x)

and then trying to use it in a different module:

# bar.py
from foo import print_x

x = 10
print_x()  # NameError

Ultimately, g is the globals in the execution context of exec. After it calls the print_x function (which was defined in a different global context), you can't expect print_x to know anything about the globals in exec's execution context -- print_x only knows the globals in it's module's context.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Ok, thank you. So, I will need to define the print_x() function using exec? Is there any other way to change the namespace of a function? – jordanwh Jun 18 '16 at 04:54
  • @jordanwh if you really want to change the globals you could create a [copy of the function](http://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function) with your own scope passed for the new functions globals. – Tadhg McDonald-Jensen Jun 18 '16 at 04:56
  • @jordanwh -- I think I've seen some (maybe cpython specific) solutions that created a new function from and old one using `types.FunctionType` or something similar. I don't know how to do it off the top of my head so you'll probably need to do some sleuthing if you really want to try to make it work ... – mgilson Jun 18 '16 at 04:56
  • @Tadhg McDonald-Jensen Perfect. Thank you. – jordanwh Jun 18 '16 at 04:57