eval calling lambda don't see self
Here is a simple code illustrating the essence of a problem:
class test:
def __开发者_JS百科init__(self):
self.var = 0
def set(self, val):
self.var = val
print eval('map(lambda x: self.var*x, [1,2,3,4,5])')
f = test()
f.set(10)
It says
NameError: global name 'self' is not defined
I know many people don't like eval but in my case I have to use it because it executes a math formula from the string entered by a user during programm execution. Any suggestions is highly appreciated! Thanks in advance!
Try:
eval('map(lambda x, self=self: self.var*x, [1,2,3,4,5])')
The odd self=self
will create a copy of self
from the outer context into the inner context (the "body" of the lambda expression).
This is a tricky situation. First of all as workaround you can use:
class test:
def __init__(self):
self.var = 0
def set(self, val):
self.var = val
print eval('map(lambda x,self=self: self.var*x, [1,2,3,4,5])')
f = test()
f.set(10)
The reason is not simple to explain... but let's try.
When you write
lambda x: self.var * x
what is created is a "closure", that will capture the current variable "self" as a non-local variable in the lambda expression because self is a local variable in the current environment.
When this lambda is built by eval
however this local variable self
is not visible inside eval
and therefore the lambda function generated will refer to the global variable self
that doesn't exist in this case.
Eval() also supports setting global and local variables respectively so you could do something like this:
class test:
def __init__(self):
self.var = 0
def set(self, val):
self.var = val
print eval('map(lambda x: self.var*x, [1,2,3,4,5])', dict(globals().items() + [('self', self)]))
f = test()
f.set(10)
Update: The above example now maintains previous global and local variables.
While I'm sure there is a way to do this without eval, have you tried using string formatting?
eval('map(lambda x: %s*x, [1,2,3,4,5])'%self.var)
The more generic answer is to pass local variables into the eval environment
The eval function supports two additional parameters, the global and locals variables. So, for instance, you can solve the issue without altering the function by passing:
eval(map(lambda x: self.var*x + myvar, [1,2,3,4,5]), dict(self=self, myvar=123))
精彩评论