eval叫lambda看不到自己

时间:2011-09-08 14:37:18

标签: python

这是一个简单的代码,说明了问题的本质:

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])')
f = test()
f.set(10)

它说

NameError: global name 'self' is not defined

我知道很多人不喜欢eval,但在我的情况下我必须使用它,因为它在程序执行期间从用户输入的字符串中执行数学公式。 任何建议都非常感谢!提前谢谢!

5 个答案:

答案 0 :(得分:9)

尝试:

eval('map(lambda x, self=self: self.var*x, [1,2,3,4,5])')

奇数self=self将从外部上下文创建self的副本到内部上下文(lambda表达式的“主体”)。

答案 1 :(得分:7)

这是一个棘手的情况。首先,您可以使用以下方法:

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)

理由并不容易解释......但是试试吧。

写作时

 lambda x: self.var * x

创建的是一个“闭包”,它将当前变量“self”捕获为lambda表达式中的非局部变量,因为self是当前环境中的局部变量。

当这个lambda由eval构建时,但是self中的局部变量eval不可见,因此生成的lambda函数将引用全局在这种情况下不存在的变量self

答案 2 :(得分:7)

Eval()还支持分别设置全局和局部变量,因此您可以执行以下操作:

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)

更新:以上示例现在维护以前的全局和局部变量。

答案 3 :(得分:2)

虽然我确定有一种方法可以在没有eval的情况下执行此操作,但您是否尝试过使用字符串格式化?

eval('map(lambda x: %s*x, [1,2,3,4,5])'%self.var)

答案 4 :(得分:0)

更通用的答案是将局部变量传递到eval环境

eval function支持另外两个参数,即全局和局部变量。因此,例如,您可以通过传递:

来解决问题而无需更改函数
eval(map(lambda x: self.var*x + myvar, [1,2,3,4,5]), dict(self=self, myvar=123))