Are Python functions' global view inherited from callers, and can I inject things that aren't actually global?

Viewed 26

While trying to figure out this answer I see from the documentation that every stack frame has an f_globals member.

Is that designed to be manipulated on a per-callee basis?

I want to advertise a local variable to callees of a function, in a sort of "while we're within this call tree, this is the context decorators and utilities will use" way, without having to modify every function in the potential call graph to pass this along. It's not a great decorator when you have to rewrite the decorated function, after all.

1 Answers

So here's what I think I've learned so far:

The call stack can contain different values of r_globals for each frame because each function has "global" state that is shared within the module in which it is defined and not the whole execution state. Since calls can cross between modules, r_globals can be different in every frame.

Even if you create a new module and copy a function into it, __globals__ is a read-only member of that function object, so when you call it its globals revert back to the original module where it was first defined, not the modified globals of its adopted parent.

Similarly, if you use exec() with modified globals, or if you can build your own copy of the callee code with modified __globals__ you'll only get one layer deep before a subsequent call reverts back to that function's original view of its globals.


It looks like the intended solution to this problem is context variables, which addresses some problems that thread-local storage fails to handle.

Related