Python 2中的Eval范围与3

时间:2015-03-30 00:22:54

标签: python python-3.x compatibility 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())

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

它在Python 2中运行良好:

▶ python --version
Python 2.7.8
▶ python eval.py
[0.5, 0.25, 0.75]

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

def apply_op():
    x, y, z = [0.5, 0.25, 0.75]
    return [eval("x"), eval("y"), eval("z")]

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

2 个答案:

答案 0 :(得分:25)

错误跟踪器中存在已关闭问题:Issue 5242

此错误的解决方案无法修复

该问题的一些评论如下:

  

这是预期的,不会轻易修复。原因是那份清单   3.x中的理解使用函数命名空间“在引擎盖下”(在2.x中,   它们的实现就像一个简单的for循环)。因为内在的功能   需要知道从封闭的命名空间,名称中得到什么名称   eval()中引用的函数不能来自封闭函数。他们一定   无论是本地人还是全球人。

     

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

答案 1 :(得分:4)

如果你想:

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())

为了工作你需要捕获本地和全局,因为问题eval(o)eval(o, globals(), locals())相同,但eval出现在生成器函数中这些函数的结果与eval没有包装函数时的结果相同,因此将它们捕获到生成器外部并在内部使用它们:

def apply_op():
    x, y, z = [0.5, 0.25, 0.75]
    op = "x,y,z"
    _locals = locals()
    _globals = globals()
    return [eval(o, _globals, _locals) for o in op.split(",")]
print(apply_op())

或者更好,因为x,y,z是本地人,而字符串只是变量名称:

def apply_op():
    x, y, z = [0.5, 0.25, 0.75]
    op = "x,y,z"
    _locals = locals()
    return [_locals[o] for o in op.split(",")]
print(apply_op())