我在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")]
这是预期的行为,还是一个错误?
答案 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())