eval 调用 lambda 无法访问 self
这里有一段简单的代码,展示了一个问题的本质:
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 个回答
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)
更新: 上面的例子现在可以保留之前的全局变量和局部变量了。
8
这是一种比较棘手的情况。首先,作为一种解决方法,你可以使用:
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”当作一个非本地变量捕获,因为在当前环境中,self是一个局部变量。
但是,当这个闭包通过 eval
来构建时,这个局部变量 self
在 eval
内部是不可见的,因此生成的闭包函数会引用一个全局变量 self
,而在这种情况下,这个全局变量并不存在。
12
试试这个:
eval('map(lambda x, self=self: self.var*x, [1,2,3,4,5])')
这里的 self=self
有点奇怪,它的作用是把外部的 self
复制到内部的环境中,也就是在这个 lambda 表达式的“主体”里。