为什么lambda in eval函数无法关闭用户定义的'locals'字典中的变量?

时间:2018-05-29 08:19:37

标签: python lambda eval

我想使用内置的eval函数评估lambda表达式,并在'locals'参数中定义变量y。遗憾的是,结果函数不起作用:

>>>x = eval('lambda: print(y)',{},{'y':2})
>>>x()
Traceback (most recent call last):
  File "<pyshell#75>", line 1, in <module>
    x()
  File "<string>", line 1, in <lambda>
NameError: name 'y' is not defined

但是在'globals'参数中定义了y,它确实有效:

>>> x = eval('lambda: print(y)', {'y': 2},{})
>>> x()
2

据我所知,lambda表达式应该捕获整个当前帧,包括globals和locals参数中定义的所有变量。

那么为什么Python的行为如此?

2 个答案:

答案 0 :(得分:0)

x = eval('lambda: print(y)',{},{'y':2})在第一部分更改参数顺序中不等于此行x = eval('lambda: print(y)', {'y': 2},{}),它应该可以正常工作

答案 1 :(得分:0)

非常简单:传递一个填充的locals目录并不会改变python解析函数代码的方式,并决定哪些名称是本地名称,哪些名称是全局名称。

本地名称是在函数体内绑定的参数名称和名称,而不是明确声明的全局变量或非本地变量。这里,y不是一个参数,并且没有绑定在函数体内(无论如何都不可能在lambda中),所以它被编译器标记为全局。

现在那些全局和本地环境是那些用来评估表达式本身的环境(这里是完整的&#39; lambda:print(y)&#39;表达式),而不是&#34; lambda的本地环境&# 39; s body&#34 ;,所以即使有办法让y本地的功能部门(提示:那里有一个 - 但它不会解决你的问题问题)这个名字仍然不会自动地#34;设置为&#39; y&#39;传递给eval的当地人dict中的值。

但这实际上不是问题 - 由eval("lambda: y", {"y":42})创建的函数捕获传递给eval的全局变量dict并使用它代替模块/脚本/无论全局变量,因此它将起作用预期:

Python 3.4.3 (default, Nov 28 2017, 16:41:13) 
[GCC 4.8.4] on linux
>>> f = eval("lambda: y+2", {'y':2}, {})
>>> f()
4
>>> y = 42
>>> f()
4

现在你有了解释,我想补充一点 eval()是非常危险的,而且往往是更好的解决方案,这取决于你的确切问题&# 39;重新尝试解决。你没有提供任何上下文,所以不可能多说,但我不得不说我实际上很难想到f = eval("lambda: whatever")之类的具体用例。