Why lambda in eval function can't closure the variables in the user-defined 'locals' dict?

北城以北 提交于 2020-01-15 20:13:50

问题


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

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

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

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

So why does Python behave like this?


回答1:


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.

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.

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.

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

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").




回答2:


x = eval('lambda: print(y)',{},{'y':2}) is not equal to this line x = eval('lambda: print(y)', {'y': 2},{}) in first part change params order and it should work



来源:https://stackoverflow.com/questions/50579541/why-lambda-in-eval-function-cant-closure-the-variables-in-the-user-defined-loc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!