开发者

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))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜