【问题标题】:globals() vs locals() mutabilityglobals() vs locals() 可变性
【发布时间】:2015-05-18 23:17:49
【问题描述】:

在 Python 中,globals() 返回全局符号表的表示,而locals() 返回本地状态的表示。虽然两者都返回字典,但对globals() 的更改会在全局符号表中生效,而对locals() 的更改则无效。

为什么会这样?

【问题讨论】:

  • @BartoszKP:实际上没有一个答案是正确的。
  • @MartijnPieters 接受的答案本质上与您所说的相同-您不应该修改本地人,因为它会产生未定义的行为。如果您认为您的答案更好,也许您可​​以考虑将其发布在此处,而不是此处。如果您坚持,我不会反对另一个问题作为这个问题的副本。但似乎你不需要为此投票:)
  • @BartoszKP:不过可能有更好的骗子。
  • @MartijnPieters 你是对的。这是我找到的最好的,但我承认我在这上面花的时间不超过 5 分钟 :)

标签: python state python-internals mutability


【解决方案1】:

函数局部变量在编译时经过高度优化和确定,CPython 建立在无法在运行时动态更改已知局部变量的基础上。

解码函数字节码时可以看到:

>>> import dis
>>> def foo():
...     a = 'bar'
...     return a + 'baz'
... 
>>> dis.dis(foo)
  2           0 LOAD_CONST               1 ('bar')
              3 STORE_FAST               0 (a)

  3           6 LOAD_FAST                0 (a)
              9 LOAD_CONST               2 ('baz')
             12 BINARY_ADD          
             13 RETURN_VALUE        

LOAD_FASTSTORE_FAST 操作码使用 indices 来加载和存储变量,因为在帧上,局部变量被实现为数组。访问数组比使用哈希表(字典)更快,例如用于全局命名空间。

locals() 函数在函数中使用时,会将该数组的 反射 作为字典返回。更改 locals() 字典不会将其反映回数组中。

在 Python 2 中,如果您在代码中使用 exec 语句,则优化(部分)被破坏;在这种情况下,Python 使用较慢的 LOAD_NAME opcode

>>> def bar(code):
...     exec code
...     return a + 'baz'
... 
>>> dis.dis(bar)
  2           0 LOAD_FAST                0 (code)
              3 LOAD_CONST               0 (None)
              6 DUP_TOP             
              7 EXEC_STMT           

  3           8 LOAD_NAME                0 (a)
             11 LOAD_CONST               1 ('baz')
             14 BINARY_ADD          
             15 RETURN_VALUE        

另见bug report against Python 3,其中exec()(Py3 中的一个函数)不再允许您设置本地名称:

动态修改函数的局部变量不是 可能没有几个后果:通常,函数局部变量不是 存储在字典中,而是一个数组,其索引在 从已知的语言环境编译时间。这至少与新的 本地人由 exec 添加。 旧的 exec 语句规避了这一点,因为 编译器知道,如果没有全局/本地参数的 exec 发生 在函数中,该命名空间将是“未优化的”,即不使用 locals 数组。 由于 exec() 现在是一个普通函数,编译器会 不知道“exec”可能绑定到什么,因此不能处理的是 特别是。

【讨论】:

  • 为什么 globals() 的行为方式不同?
  • @lumisota:因为 globals 是 a) 分层的(它也进入内置函数)并且必须支持在运行时更改(使用 global 关键字,以及在运行时添加到模块命名空间) .
猜你喜欢
  • 2019-02-18
  • 1970-01-01
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-05
相关资源
最近更新 更多