globals()vs locals()可变性

时间:2015-03-16 17:52:29

标签: python state python-internals mutability

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

为什么会这样?

1 个答案:

答案 0 :(得分:7)

函数本地是高度优化的,并且在编译时确定,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添加。 旧的执行声明绕过了这个,因为   编译器知道如果没有globals / locals的exec发生了   在一个函数中,该命名空间将是“未优化的”,即不使用   locals array。由于exec()现在是一个普通的函数,编译器就是这样   不知道“exec”可能会受到什么约束,因而无法对待   特别