I'd like a function in my module to be able to access and change the local namespace of the script that's importing it. This would enable functions like this:
>>> import foo
>>> foo.set_a_to_three()
>>> a
3
>>>
Is this possible in Python?
An answer was generously provided by @omz in a Slack team:
import inspect
def set_a_to_three():
f = inspect.currentframe().f_back
f.f_globals['a'] = 3
This provides the advantage over the __main__
solution that it works in multiple levels of imports, for example if a
imports b
which imports my module, foo
, foo
can modify b
's globals, not just a
's (I think)
However, if I understand correctly, modifying the local namespace is more complicated. As someone else pointed out:
It breaks when you call that function from within another function. Then the next namespace up the stack is a fake dict of locals, which you cannot write to. Well, you can, but writes are ignored.
If there's a more reliable solution, that'd be greatly appreciated.
To let the module access your script's namespace, you will have to pass the namespace to the function. For example:
>>> import foo
>>> foo.set_a_to_three(globals(), locals())
>>> a
3
The inside of the code would look like this:
def set_a_to_three(globalDict, localDict):
localDict['a'] = 3
Sidenote: In this case, the globals dictionary is not needed but in cases where you need to modify global variable, you will need to use the globals dictionary. I have included it here for this reason to make the function extensible.
However, it would be easier to just set a = 3
as Eli Sadoff said. It isn't a good practice to pass namespaces to other programs.
Disclaimer: This solution can only modify global variables, so it's not perfect. See Is it good practice to use import __main__
? for pros and cons.
In foo.py:
import __main__
def set_a_to_three():
__main__.a = 3
__main__
is a name given to the current top-level program. For example, if you import foo
from a module bar
, then bar
can be referenced with the name __main__
. If you import foo
from bar
, which was initially imported from a module qux
, then qux
is __main__
, etc.
bar -> foo
bar is __main__
qux -> bar -> foo
qux is __main__
If you actually want to modify variables in bar
rather than qux
, for example because qux
contains unit tests, you can use something like this:
import sys
import __main__
if "bar" in sys.modules:
__main__ = sys.modules["bar"]
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