1

Consider this working code:

x=123

def printx():
     print(x)

If I execute printx() the output would be 123 as x value exists in locals() and printx sees that.

I can also get x value like this:

locals()["x"]

But I need to run my function in exec with global and local parameters supplied, so I wrote this code, which should be identical in purpose to the first snippet:

glo = dict()
loc = dict()
exec('x=123', glo, loc)
exec('def printx():\n    print(x)', glo, loc)

However, when I call printx() I get this error:

exec('printx()', glo, loc)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "<string>", line 2, in printx
NameError: name 'x' is not defined

Yet both loc["x"] and eval('x', glo, loc) return 123 as expected.

How can I make locals and globals available for my printx function? I want printx to behave the same in exec with context?

rfg
  • 1,331
  • 1
  • 8
  • 24
  • 2
    *"I need to run my function in `exec`"* - you probably don't – DeepSpace Apr 27 '21 at 20:36
  • @TomKarzes not sure what you're talking about? I started `python` interpreter and executed the code I posted. There's nothing else. It's Python 3.8.7. – rfg Apr 27 '21 at 20:40
  • @rfg Sorry, you're right, at the top-level `locals()` shows global variable bindings - I had forgotten that. You can compare it with `globals()`. In fact, at the top-level, they return the exact same `dict`, and in fact `locals() is globals()` is true at the top level. – Tom Karzes Apr 27 '21 at 20:44

1 Answers1

2

If a local dict is provided, "eval" runs in that local namespace. All changes go in that local namespace. You can see that by printing loc after your commands. Both x and printx are in that namespace. Calling a function establishes a new local namespace. Python doesn't nest namespaces, so all it has available is its new (empty) local namespace and the global namespace, and x is in neither of those.

You should probably run your first two evals with the global namespace only. That way, your code will work, even if it is a horrible way to do Python programming.

Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • Thank you! That's exactly what I need. – rfg Apr 27 '21 at 20:50
  • 1
    Technically, Python will nest namespaces (it's how closures work), but it's not something `eval`/`exec` supports; the locals aren't treated as a closure scope around any functions defined in the string being executed. C'est la vie. – ShadowRanger Apr 28 '21 at 18:48