我发现了 python exec()
函数的奇怪行为。这是代码:
variables = {
('foo', 6),
('bar', 42)
}
def func():
for varData in variables:
varName, varValue = varData
localVarToEvaluate = varName + ' = varValue'
try:
#exec(localVarToEvaluate, globals(), locals())
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if varName not in locals():
print("Variable names '", varName, "can't be found in local scope!")
if 'foo' in locals():
print("'foo' OK:", foo) # exception here
else:
print("'foo' not available!")
if 'bar' in locals():
print("'bar' OK:", bar)
else:
print("'bar' not available!")
func()
我希望变量 foo
和 bar
在 exec()
调用结束时创建并打印,情况就是这样Python 2.7。上面的所有内容(在 3.3、3.4、3.6 和 3.7 上测试)都会抛出异常,即 foo
未定义:
Exception has occurred: NameError
name 'foo' is not defined
这里奇怪的是,通过运行 locals()
、globals()
可以看到 foo
和 bar
或 dir()
(也由 if
语句确认),但是,代码/解释器看不到它。
更奇怪的是,调试此脚本并解析任何变量均成功(我已在 # exception here
上设置了断点,并使用 VS Code 在调试窗口中键入 foo
。 foo
已正确解析,值为“6”。
如果相同的代码(函数 func()
内的内容)未包装在函数中,则这将按预期工作,foo
和 bar
打印出来。
知道这里发生了什么吗?
<小时/>更新:我进一步简化了这个问题:
# take 1, create local variable 'foo' with value 6. Not in function.
varName = 'foo'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if 'foo' in locals():
# print(locals()['foo']) # (1)
# print(foo) # (2)
print("'foo' OK:", foo) # (3)
# take 2, create local variable 'bar' with value 42
def func2():
varName = 'bar'
varValue = 42
localVarToEvaluate = varName + ' = varValue'
try:
exec(localVarToEvaluate)
except Exception as err:
print(str(err))
if 'bar' in locals():
# print(locals()['bar']) # (1)
# print(bar) # (2)
#print("'bar' OK:", bar) # (3)
pass # uncomment any line above
func2()
当这段代码执行时,首先:
'foo' OK: 6
被打印,然后引发此异常:
Exception has occurred: NameError
name 'bar' is not defined
...
请注意,两个代码是相同的,除了“bar”变量是在函数 func2()
内部创建的。
我感兴趣的不是解决方法,而是解释,为什么会这样以及为什么点(1)有效,而(2)和(3)则无效。请注意,bar
变量在 locals()
中可见,但无法通过直接调用来访问它 - 但前提是它是在函数内部创建的!
最佳答案
I've reported a bug on a Python Issue Tracker ,官方答案是:
This is currently by design, which means 3.8 is likely the only viable place it can change. It's also not Windows specific so I removed that component (people may remove themselves from nosy).
...
Currently it's basically a read-only proxy, as locals are optimized within functions which is why you can't see updates via the duct.
底线,以这种方式使用的 exec()
在函数内部是无用的。
关于Python exec() 函数在 2.7 以上版本中损坏?错误: 'name' not defined,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55239875/