分配顺序对"exec expr in globals(), locals()"出乎意料地重要



Python 2.X 中的以下代码打印"a : 2",如您所料:

def f():
  #a = 1
  exec "a = 2" in globals(), locals()
  for k,v in locals().items(): print k,":",v
  #a = 3
f()

但是,如果您取消注释"a = 1",那么它会打印"a : 1",这是我没想到的。更奇怪的是,如果您取消注释"a = 3"行,那么它根本不会打印任何内容,这是我绝对没想到的(我有一个令人困惑的错误,我将其提炼为那个错误)。

我认为答案隐藏在 locals() 和 globals() 的文档中,或者可能埋藏在其他类似的问题中,但我认为值得指出这种表现形式。

我很想了解 Python 解释器在这里的想法,以及解决方法的建议。

旧的Python 2的exec将更改字节码以搜索本地和全局命名空间。

当您在全局中定义a = 2时,这是在注释a = 1时找到的那个。当您取消注释a = 3 时,这是"找到"但尚未定义的a

如果您阅读了 Eli Bendersky 撰写的这篇精彩文章中如何处理符号表,您可以更好地了解局部变量的处理方式。

您不应该对此类代码使用exec(我希望这不是生产代码),当您将代码移植到 Py3k 时,它无论如何都会中断:

Python 3 的 exec 函数不再是一个语句,因此无法更改它所在的环境。


可能我应该直接进入正题:

如果你正在做所有这些动态命名的事情,你应该使用字典:

def f():
    data = {'a': 1}
    data['a'] = 2
    if ...:
        data['a'] = 3

来自locals函数文档:

注意:不应修改此字典的内容;更改可能不会影响解释器使用的局部变量和自由变量的值。

检查:

>>> def f():
    a = 1
    print(locals())
    locals()['a']=2
    print(a,locals())

>>> f()
{'a': 1}
1 {'a': 1}

所以你不能通过locals()函数修改局部上下文

最新更新