python – globals()vs locals()mutability
作者:互联网
在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
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中的函数)不允许您再设置本地名称:
To modify the locals of a function on the fly is not
possible without several consequences: normally, function locals are not
stored in a dictionary, but an array, whose indices are determined at
compile time from the known locales. This collides at least with new
locals added by exec. The old exec statement circumvented this, because
the compiler knew that if an exec without globals/locals args occurred
in a function, that namespace would be “unoptimized”, i.e. not using the
locals array. Since exec() is now a normal function, the compiler does
not know what “exec” may be bound to, and therefore can not treat is
specially.
标签:python,python-internals,state,mutability 来源: https://codeday.me/bug/20190612/1223194.html