lum*_*ota 4 python state mutability python-internals
在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
Run Code Online (Sandbox Code Playgroud)
的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
Run Code Online (Sandbox Code Playgroud)
另请参阅针对Python 3的此错误报告,其中exec()(Py3中的函数)不允许您再设置本地名称:
如果没有几个结果,则无法动态修改函数的局部函数:通常,函数局部函数不存储在字典中,而是存储在数组中,其索引在编译时从已知语言环境确定.这至少与exec添加的新本地人发生冲突. 旧的exec语句规避了这一点,因为编译器知道如果函数中没有发生全局/局部因子的exec,那么该命名空间将"未经优化",即不使用本地数组. 由于exec()现在是一个普通函数,编译器不知道"exec"可能绑定到什么,因此无法特别处理.