Python 评估呼叫lambda don';我看不见自己
下面是一个简单的代码,说明了问题的本质:Python 评估呼叫lambda don';我看不见自己,python,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 d
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,但在我的例子中,我不得不使用它,因为它根据用户在程序执行期间输入的字符串执行数学公式。
非常感谢您的任何建议!提前谢谢 试试看:
eval('map(lambda x, self=self: self.var*x, [1,2,3,4,5])')
奇怪的
self=self
将创建一个self
的副本,从外部上下文复制到内部上下文(lambda表达式的“主体”)。虽然我确信有一种不使用eval的方法可以做到这一点,但您是否尝试过使用字符串格式
eval('map(lambda x: %s*x, [1,2,3,4,5])'%self.var)
这是一个棘手的局面。首先,作为解决方法,您可以使用:
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
。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)
更新:以上示例现在维护以前的全局和局部变量。更通用的答案是将局部变量传递到eval环境中 支持两个附加参数,即全局变量和局部变量。因此,例如,您可以通过传递以下消息来解决问题,而无需更改函数:
eval(map(lambda x: self.var*x + myvar, [1,2,3,4,5]), dict(self=self, myvar=123))
好办法!这就是我要找的!:)非常感谢你@aliko如果答案解决了你的问题,你应该接受它(左边计票下面的“V”标记)。我希望我可以将这里的所有消息标记为已接受,但不幸的是,我只能标记一条…(让它成为第一个正确答案:)“数学公式”如
\uu import\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
?@dan04:您的公式中一定有错误。它在Windows上不起作用:),而这种方法正在起作用!Python是关于选择的:)我没想到会在几分钟内收到如此有用的答案。而你的是最基本的…)这是一个很好的提问的地方!:)您收到了有用的答案,因为您以简化的形式清楚地陈述了您的问题,解释了您为什么要做您正在做的事情,并且因为问题很有趣。如果你所有的问题都是这样,你会得到很好的回答。此外,如果你还不知道,当你决定哪个答案是你问题的最佳解决方案时,在数字和箭头下方有一个小复选标记,可以让你将其标记为“已接受”。这种方法的唯一缺点是它对eval隐藏全局值。@aliko谢谢,你是对的。我已经更新了我的示例以维护以前的全局。这个解决方案的优点是不必更改lambda签名,很好。