Since I've been poking around in this area of CPython lately, here's some trivia associated with frame objects.
First, one might wonder if code executing at the module level literally has a CPython frame struct with
f_locals
being the same as
f_globals
, or if the C code just leaves
f_locals
null and fixes things up behind the scenes when you look from Python code. The answer turns out to be that CPython frame structures always have a real
f_locals
(Python) dictionary, and in module level code it is just another reference to the globals as you'd expect.
This surprised me because I had always assumed that
f_locals
dictionaries for function-level frames were only materialized on (rare) demand. Instead there's always a dictionary, although its contents are allowed to get out of date with the real local variables as long as no Python code is looking at it.
(There are various interesting efficiency hacks to make creation and destruction of frame objects faster than you might expect.)
Second and probably obviously: there's no way to directly update the builtins namespace. This is both a language issue (there's no
builtin
analog to the
global
keyword) and an issue with the bytecode interpreter ; in order to support direct updates of the builtin namespace, the bytecode interpreter would need a new
STORE_BUILTIN
opcode, as
STORE_GLOBAL
naturally only updates the
f_globals
namespace.
Now, consider the following code:
eval = eval
def t():
global file
file = file
This peculiar do-nothing code actually does do something: it creates module-level shadows of the
eval
and
file
builtins. This is one of the least obvious cases in which the left hand side of an assignment can be in a different namespace than the right hand side despite using the exact same variable names. (Or not, if you've already executed these statements once.)
(Previously I said that there were only two cases of such namespace differences; I was wrong then, or at least insufficiently perverse.)