eval 调用 lambda 无法访问 self

16 投票
5 回答
3945 浏览
提问于 2025-04-17 01:48

这里有一段简单的代码,展示了一个问题的本质:

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 来构建时,这个局部变量 selfeval 内部是不可见的,因此生成的闭包函数会引用一个全局变量 self,而在这种情况下,这个全局变量并不存在。

12

试试这个:

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

这里的 self=self 有点奇怪,它的作用是把外部的 self 复制到内部的环境中,也就是在这个 lambda 表达式的“主体”里。

撰写回答