在 Python 中,globals()
返回全局符号表的表示,同时locals()
返回局部状态的表示。虽然两者都返回字典,但更改globals()
会在全局符号表中生效,而更改locals()
不会生效。
为什么会这样?
在 Python 中,globals()
返回全局符号表的表示,同时locals()
返回局部状态的表示。虽然两者都返回字典,但更改globals()
会在全局符号表中生效,而更改locals()
不会生效。
为什么会这样?
函数局部变量在编译时经过高度优化和确定,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_FAST
和STORE_FAST
操作码使用索引来加载和存储变量,因为在帧上,局部变量被实现为数组。访问数组比使用哈希表(字典)更快,例如用于全局命名空间。
该locals()
函数在函数中使用时,会将该数组的反射作为字典返回。更改locals()
字典不会将其反映回数组中。
在 Python 2 中,如果您exec
在代码中使用该语句,则优化(部分)被破坏;在这种情况下, Python 使用较慢的LOAD_NAME
操作码:
>>> 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
另请参阅此针对 Python 3 的错误报告,其中exec()
(Py3 中的一个函数)不再允许您设置本地名称:
动态修改函数的局部变量是不可能的,没有几个后果:通常,函数局部变量不存储在字典中,而是存储在数组中,其索引是在编译时从已知的语言环境中确定的。这至少与 exec 添加的新本地人发生冲突。 旧的 exec 语句规避了这一点,因为编译器知道,如果函数中出现没有全局/局部参数的 exec,则该命名空间将是“未优化的”,即不使用 locals 数组。 由于 exec() 现在是一个普通函数,编译器不知道“exec”可能绑定到什么,因此不能特殊处理。