In Python, globals()
returns a representation of the global symbol table, while locals()
returns a representation of the local state. While both return a dictionary, changes to globals()
are effected in the global symbol table, while change to locals()
have no effect.
Why is this the case?
Function locals are highly optimised and determined at compile time, CPython builds on not being able to alter the known locals dynamically at runtime.
You can see this when decoding a function bytecode:
>>> 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
The LOAD_FAST
and STORE_FAST
opcodes use indices to load and store variables, because on a frame the locals is implemented as an array. Access to an array is faster than using a hash table (dictionary), such as used for the global namespace.
The locals()
function, when used in a function, then returns a reflection of this array as a dictionary. Altering the locals()
dictionary won't then reflect that back into the array.
In Python 2, if you use the exec
statement in your code then the optimisation is (partly) broken; Python uses the slower LOAD_NAME
opcode in that case:
>>> 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
Also see this bug report against Python 3 where exec()
(a function in Py3) doesn't allow you to set local names anymore:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With