为什么eval函数中的lambda无法关闭用户定义的"locals"字典中的变量? [英] Why lambda in eval function can't closure the variables in the user-defined 'locals' dict?

查看:70
本文介绍了为什么eval函数中的lambda无法关闭用户定义的"locals"字典中的变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用内置的eval函数对lambda表达式求值,并在'locals'参数中定义变量y.遗憾的是结果功能不起作用:

I want to evaluate a lambda expression using the built-in eval function, with a variable y defined in the 'locals' argument. Sadly the result function doesn't work:

>>>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,它确实可以工作:

But with y defined in the 'globals' argument, it does work:

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

据我了解,lambda表达式应该已经捕获了整个当前帧,包括在globals和locals参数中定义的所有变量.

As I understand, the lambda expression should have captured the whole current frame including all the variables defined in the globals and locals arguments.

那Python为什么会这样表现呢?

So why does Python behave like this?

推荐答案

很简单:传递一个填充的locals目录不会改变python解析函数代码并确定哪些名称是局部名称和哪些是全局名称的方式.

Quite simply: passing a populated locals directory doesn't change the way python parses a function code and decides which names are locals and which are globals.

本地名称是参数名称和绑定在函数体内的名称,并且未明确声明为全局变量或非本地变量.在这里,y不是参数,并且没有绑定在函数主体内(无论如何在lambda中都是不可能的),因此编译器将其标记为全局.

Local names are arguments names and names that are bound within the function's body and not explicitely declared globals or non-locals. Here, y is not an argument, and is not bound within the function's body (which is impossible in a lambda anyway) so it is marked by the compiler as global.

现在,那些全局和局部环境是用于评估表达式本身的环境(此处是完整的"lambda:print(y)"表达式),而不是"lambda身体的局部环境",因此即使有一种方法使y局部于函数的主体(提示:有一个-但这无法解决您的问题),此名称仍不会自动"设置为传递给.

Now those global and local environment are those used to evaluate the expression itself (here the full 'lambda: print(y)' expression), not "the local environment for the lambda's body", so even if there was a way to make y local to the function's body (hint: there's one - but it won't solve your problem) this name would still not be "automagically" set to the the 'y' value in the locals dict passed to eval.

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

BUT this is actually not a problem - the function created by eval("lambda: y", {"y":42}) captures the globals dict passed to eval and uses it in place of the module/script/whatever globals, so it will work as expected:

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()非常危险,而且通常情况下,还有一个更好的解决方案,这取决于您要解决的确切问题.您没有提供任何上下文,因此无法透露更多信息,但是我不得不说,实际上我很难想到f = eval("lambda: whatever")这样的事情的具体用例.

Now you have the explanation, I whish to add that eval() is very dangerous and most often than not there's a much better solution, depending on the exact problem you're trying to solve. You didn't provide any context so it's impossible to tell more but I have to say I actually have a hard time thinking of a concrete use-case for such a thing as f = eval("lambda: whatever").

这篇关于为什么eval函数中的lambda无法关闭用户定义的"locals"字典中的变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆