rfg
rfg

Reputation: 1636

Function does not see locals in exec with supplied locals

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?

Upvotes: 1

Views: 489

Answers (1)

Tim Roberts
Tim Roberts

Reputation: 54812

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.

Upvotes: 2

Related Questions