I have the following code
def foo(q, s):
a = 1
f = lambda x : eval(s)
return f(1)
foo(1, "x a q")
I would expect the function call to return 3
, however I get a NameError
instead. I assume that's because eval
doesn't have access to the local scope. However I wasn't able to make it work even after passing locals()
or a dictionary with the objects.
CodePudding user response:
So, this is clearly documented:
Note,
eval()
does not have access to the nested scopes (non-locals) in the enclosing environment.
So, you could capture the non-local scope and force eval
to use it. How exactly you make this work is up to you and your use-case, here is one example:
>>> def foo(q, s):
... a = 1
... nonlocals = locals()
... def f(x):
... return eval(s, {**locals(), **nonlocals})
... return f(1)
...
>>> foo(1, "x a q")
3
Some things to note:
- I used the
locals()
of the functionf
first. You could switch the order if you want, and it won't matter if and only if there would be no name collisions. Otherwise it is up to you which takes precedence - In the more recent versions of Python,
{**locals(), **nonlocals}
could belocals() | nonlocals
- I didn't use a lambda expression here, to comport with PEP8 style guidelines. Don't assign the result of a
lambda
expression to a name, that defeats the entire purpose of lambda expressions, which are to be anonymous. - You should consider whether you really need to use
eval
here. It is likely not the best solution to your problem.