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个相似问题进行合理的分析

4 回复

作用域问题,定义与声明混乱了,查看字节码能看得出区别


事实 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 结果,循环引用不应该忽视

回到顶部