Python 2中的Eval范围与3

Pat*_*ime 26 python compatibility python-3.x python-3.4

我在Python 3中遇到了奇怪的eval行为 - 当在列表推导中调用eval时,不会拾取局部变量.

def apply_op():
    x, y, z = [0.5, 0.25, 0.75]
    op = "x,y,z"
    return [eval(o) for o in op.split(",")]
print(apply_op())
Run Code Online (Sandbox Code Playgroud)

它在Python 3中出错:

? python --version
Python 3.4.3
? python eval.py
Traceback (most recent call last):
  File "eval.py", line 7, in <module>
    print(apply_op())
  File "eval.py", line 5, in apply_op
    return [eval(o) % 1 for o in op.split(",")]
  File "eval.py", line 5, in <listcomp>
    return [eval(o) % 1 for o in op.split(",")]
  File "<string>", line 1, in <module>
NameError: name 'x' is not defined
Run Code Online (Sandbox Code Playgroud)

它在Python 2中运行良好:

? python --version
Python 2.7.8
? python eval.py
[0.5, 0.25, 0.75]
Run Code Online (Sandbox Code Playgroud)

将其移出列表理解之外可以解决问题.

def apply_op():
    x, y, z = [0.5, 0.25, 0.75]
    return [eval("x"), eval("y"), eval("z")]
Run Code Online (Sandbox Code Playgroud)

这是预期的行为,还是一个错误?

kou*_*iou 25

错误跟踪器中存在一个已关闭的问题:问题5242.

该错误的解决方案无法解决.

该问题的一些评论如下:

这是预期的,不会轻易修复.原因是3.x中的列表推导使用了"引擎盖下"的函数命名空间(在2.x中,它们的实现类似于简单的for循环).因为内部函数需要知道从封闭命名空间中获取什么名称,所以eval()中引用的名称不能来自封闭函数.它们必须是本地人或全球人.

eval()可能已经是一个hack,没有必要添加另一个hack来使它工作.最好摆脱eval()并找到一种更好的方法来做你想做的事情.

  • 是的,我可以使用显式内部函数在Python 2中重现相同的行为.有趣的是,Perl和JavaScript都支持内部函数,*不会*表现出这种行为:`function foo(){var x = 42; function bar(){return eval("x")}; 返回栏}; foo()()`按预期产生42,因此"内部函数需要知道从封闭命名空间获取什么名称"的要求实际上是Python的一个怪癖,而不是内部函数的一般限制. (2认同)