The result of the locals()
call inside a function is not one that you can use to actually update locals using your method. The documentation makes that clear:
locals()
Update and return a dictionary representing the current local symbol table. Free variables are returned by locals()
when it is called in function blocks, but not in class blocks. Note that at the module level, locals()
and globals()
are the same dictionary.
Note The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
The reason why you cannot update locals using this method is that they are heavily optimised within the CPython source code(a). When you call locals()
, it actually builds a dictionary (the "update and return" bit) based on these heavily optimised structures and that is what you get.
Writing a new key to that dictionary is not reflected back to the actual locals.
I believe the globals()
return value does allow updates using this method because that's already a dictionary and it just gives you a reference to it, not a copy. That's why your code works outside of a function (see the clause above stating locals()
and globals()
are the same thing in that context).
From memory, Python 2 allowed you to do something like exec "answer = 42"
and that would affect the locals. But, as with print
, this was changed from a statement to a library call in Python 3, so the execution engine really has no idea what it does under the covers, meaning it cant magically bind locals with exec("answer = 42")
.
I suppose someone could request this as a feature since it would make dynamic programming a little easier. Whether it would get through the gauntlet, I have no idea, since the fact that you can provide your own locals
dictionary to exec()
means that you already have a way to detect variables that were bound by arbitrary code. They'll just be in a separate dictionary rather then in the actual locals area.
(a) Access to locals is via known indexes into the stack-frame local variable area, computed at compile time and embedded into the actual bypte code. Being able to add/change variables dynamically would break this optimisation.
This problem was raised as an issue back in early 2009 and the outcome was that it was too difficult without losing a lot of performance.