Python中如何对6个相似问题进行合理的分析
下面有 6 个例子,都挺相似,但结果比较费解。求一个能够完整解释 6 个例子的分析。
# 例 0
def foo():
exec('y = 1 + 1')
z = locals()['y']
print(z)
foo()
输出:2
# 例 1
def foo():
exec('y = 1 + 1')
y = locals()['y']
print(y)
foo()
# 报错:KeyError: 'y'
# 例 2
def foo():
y = 1 + 1
y = locals()['y']
print(y)
foo()
# 2
# 例 3
def foo():
exec('y = 1 + 1')
boc = locals()
y = boc['y']
print(y)
foo()
# KeyError: 'y'
# 例 4
def foo():
boc = locals()
exec('y = 1 + 1')
y = boc['y']
print(y)
foo()
# 2
# 例 5
def foo():
boc = locals()
exec('y = 1 + 1')
print(locals())
y = boc['y']
print(y)
foo()
# KeyError: 'y'
{'boc': {...}}
Python中如何对6个相似问题进行合理的分析
作用域问题,定义与声明混乱了,查看字节码能看得出区别
事实 1:locals() dict 是局部变量空间的拷贝, 不等于 局部变量空间
猜想 1:exec(‘y = 1 + 1’) 相当于 locals()[‘y’] = 2
猜想 2 : 调用 locals() 会刷新对应的 dict 对象(与局部变量空间同步),把定义并赋值的局部变量加入 locals() dict,把定义但未赋值的局部变量从 locals() dict 中清除
例 5:
print(locals()) 第二次调用了 locals() ,根据猜想 2,locals() dict 和局部变量空间同步,而局部变量空间里,y 已经定义但是没有赋值,locals() dict 会清除 y,所以 KeyError
例 4:
boc = locals() 调用 locals() ,locals()[‘y’] = 2 后,没有再次调用 locals() ,locals()[‘y’] 得以保留
例 3:
locals()[‘y’] = 2 之后调用了 locals() ,locals () dict 刷新,KeyError
例 2:
y = 1+1,y 已定义并赋值,locals() dict 有 key y,输出 2
例 1:
locals()[‘y’] = 2 后,y = locals()[‘y’] 调用了 locals() ,刷新 locals() dict,KeyError
例 0:
locals()[‘y’] = 2 后执行 z = locals()[‘y’] ,调用了 locals() ,刷新 locals() dict,刷新以后仍然可以输出 2,所以有了猜想 3
猜想 3:在刷新 locals() dict 时,如果一个 key 不是局部变量,那么刷新时得以保留
参考:
[为什么 Python 里面的 locals()是只读的]( https://zhuanlan.zhihu.com/p/21815224)
谢谢解答,不过我还是觉得不够全面,详细地写了一篇文章,欢迎交流: https://neue.v2ex.com/t/565190
主要是例 5 的 print 结果,循环引用不应该忽视

